All-in-One Event Calendar - Version 1.10.3

Version Description

Download this release

Release Info

Developer jbutkus
Plugin Icon 128x128 All-in-One Event Calendar
Version 1.10.3
Comparing to
See all releases

Code changes from version 1.10.2 to 1.10.3

all-in-one-event-calendar.php CHANGED
@@ -5,7 +5,7 @@
5
  * Description: A calendar system with month, week, day, agenda views, upcoming events widget, color-coded categories, recurrence, and import/export of .ics feeds.
6
  * Author: Timely
7
  * Author URI: http://time.ly/
8
- * Version: 1.10.2
9
  */
10
  @set_time_limit( 0 );
11
  @ini_set( 'memory_limit', '256M' );
@@ -24,7 +24,7 @@ define( 'AI1EC_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
24
  // ==================
25
  // = Plugin Version =
26
  // ==================
27
- define( 'AI1EC_VERSION', '1.10.2' );
28
 
29
  // ====================
30
  // = Database Version =
@@ -39,10 +39,9 @@ define( 'AI1EC_THEMES_VERSION', 8 );
39
  // ================
40
  // = Cron Version =
41
  // ================
42
- define( 'AI1EC_CRON_VERSION', 104 );
43
- define( 'AI1EC_N_CRON_VERSION', 103 );
44
  define( 'AI1EC_N_CRON_FREQ', 'daily' );
45
- define( 'AI1EC_UPDATES_URL', 'http://time.ly/standard-calendar' );
46
 
47
  // ===============
48
  // = Plugin Path =
@@ -241,25 +240,8 @@ $tmp = str_replace( 'http://', 'webcal://', AI1EC_SCRIPT_URL );
241
  // ==============
242
  define( 'AI1EC_EXPORT_URL', $tmp . "&controller=ai1ec_exporter_controller&action=export_events&cb=" . rand() );
243
 
244
- // ====================================
245
- // = Include iCal parsers and helpers =
246
- // ====================================
247
- if( version_compare( PHP_VERSION, '5.3.0' ) >= 0 ) {
248
- // Parser that requires PHP v5.3.0 or up
249
- require_once( AI1EC_LIB_PATH . '/iCalcreator-2.14/iCalcreator.class.php' );
250
- } else {
251
- // Parser that works on PHP versions below 5.3.0
252
- require_once( AI1EC_LIB_PATH . '/iCalcreator-2.10/iCalcreator.class.php' );
253
- require_once( AI1EC_LIB_PATH . '/iCalcreator-2.10/iCalUtilityFunctions.class.php' );
254
- }
255
- require_once( AI1EC_LIB_PATH . '/SG_iCal.php' );
256
- require_once( AI1EC_LIB_PATH . '/helpers/SG_iCal_Line.php' );
257
- require_once( AI1EC_LIB_PATH . '/helpers/SG_iCal_Duration.php' );
258
- require_once( AI1EC_LIB_PATH . '/helpers/SG_iCal_Freq.php' );
259
- require_once( AI1EC_LIB_PATH . '/helpers/SG_iCal_Recurrence.php' );
260
- require_once( AI1EC_LIB_PATH . '/helpers/SG_iCal_Parser.php' );
261
- require_once( AI1EC_LIB_PATH . '/helpers/SG_iCal_Query.php' );
262
- require_once( AI1EC_LIB_PATH . '/helpers/SG_iCal_Factory.php' );
263
  // include our global functions
264
  require_once( AI1EC_LIB_PATH . '/global-functions.php' );
265
 
5
  * Description: A calendar system with month, week, day, agenda views, upcoming events widget, color-coded categories, recurrence, and import/export of .ics feeds.
6
  * Author: Timely
7
  * Author URI: http://time.ly/
8
+ * Version: 1.10.3
9
  */
10
  @set_time_limit( 0 );
11
  @ini_set( 'memory_limit', '256M' );
24
  // ==================
25
  // = Plugin Version =
26
  // ==================
27
+ define( 'AI1EC_VERSION', '1.10.3' );
28
 
29
  // ====================
30
  // = Database Version =
39
  // ================
40
  // = Cron Version =
41
  // ================
42
+ define( 'AI1EC_CRON_VERSION', 105 );
43
+ define( 'AI1EC_N_CRON_VERSION', 104 );
44
  define( 'AI1EC_N_CRON_FREQ', 'daily' );
 
45
 
46
  // ===============
47
  // = Plugin Path =
240
  // ==============
241
  define( 'AI1EC_EXPORT_URL', $tmp . "&controller=ai1ec_exporter_controller&action=export_events&cb=" . rand() );
242
 
243
+ require_once( AI1EC_LIB_PATH . '/iCalcreator-2.16/iCalcreator.class.php' );
244
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  // include our global functions
246
  require_once( AI1EC_LIB_PATH . '/global-functions.php' );
247
 
app/controller/class-ai1ec-app-controller.php CHANGED
@@ -60,8 +60,7 @@ class Ai1ec_App_Controller {
60
  *
61
  * Default constructor - application initialization
62
  **/
63
- private function __construct()
64
- {
65
  global $wpdb,
66
  $ai1ec_app_helper,
67
  $ai1ec_events_controller,
@@ -73,7 +72,10 @@ class Ai1ec_App_Controller {
73
  $ai1ec_themes_controller;
74
 
75
  // register_activation_hook
76
- register_activation_hook( AI1EC_PLUGIN_NAME . '/' . AI1EC_PLUGIN_NAME . '.php', array( &$this, 'activation_hook' ) );
 
 
 
77
 
78
  // Configure MySQL to operate in GMT time
79
  $wpdb->query( "SET time_zone = '+0:00'" );
@@ -90,129 +92,130 @@ class Ai1ec_App_Controller {
90
  // Enable stats collection
91
  $this->install_n_cron();
92
 
93
- // Continue loading hooks only if themes are installed. Otherwise display a
94
- // notification on the backend with instructions how to install themes.
95
- if( ! $ai1ec_themes_controller->are_themes_available() ) {
 
96
  // Enables the hidden themes installer page
97
- add_action( 'admin_menu', array( &$ai1ec_themes_controller, 'register_theme_installer' ), 1 );
98
  // Redirects the user to install theme page
99
- add_action( 'admin_menu', array( &$this, 'check_themes' ), 2 );
100
- return;
101
  }
102
 
103
  // ===========
104
  // = ACTIONS =
105
  // ===========
106
  // Calendar theme initialization
107
- add_action( 'after_setup_theme', array( &$ai1ec_themes_controller, 'setup_theme' ) );
108
  // Create custom post type
109
- add_action( 'init', array( &$ai1ec_app_helper, 'create_post_type' ) );
110
  // Handle ICS export requests
111
- add_action( 'init', array( &$this, 'parse_standalone_request' ) );
112
  // General initialization
113
- add_action( 'init', array( &$ai1ec_events_controller, 'init' ) );
114
  // Load plugin text domain
115
- add_action( 'init', array( &$this, 'load_textdomain' ) );
116
  // Register The Event Calendar importer
117
- add_action( 'admin_init', array( &$ai1ec_importer_controller, 'register_importer' ) );
118
  // Install admin menu items.
119
- add_action( 'admin_menu', array( &$this, 'admin_menu' ), 9 );
120
  // Enable theme updater page if last version of core themes is older than
121
  // current version.
122
  if ( $ai1ec_themes_controller->are_themes_outdated() ) {
123
- add_action( 'admin_menu', array( &$ai1ec_themes_controller, 'register_theme_updater' ) );
124
  }
125
  // Add Event counts to dashboard.
126
- add_action( 'right_now_content_table_end', array( &$ai1ec_app_helper, 'right_now_content_table_end' ) );
127
  // add content for our custom columns
128
- add_action( 'manage_posts_custom_column', array( &$ai1ec_app_helper, 'custom_columns' ), 10, 2 );
129
  // Add filtering dropdowns for event categories and tags
130
- add_action( 'restrict_manage_posts', array( &$ai1ec_app_helper, 'taxonomy_filter_restrict_manage_posts' ) );
131
  // Trigger display of page in front-end depending on request
132
- add_action( 'template_redirect', array( &$this, 'route_request' ) );
133
  // Add meta boxes to event creation/edit form.
134
- add_action( 'add_meta_boxes', array( &$ai1ec_app_helper, 'add_meta_boxes' ) );
135
- add_filter( 'screen_layout_columns', array( &$ai1ec_app_helper, 'screen_layout_columns' ), 10, 2 );
136
  // Save event data when post is saved
137
- add_action( 'save_post', array( &$ai1ec_events_controller, 'save_post' ), 10, 2 );
138
  // Delete event data when post is deleted
139
- add_action( 'delete_post', array( &$ai1ec_events_controller, 'delete_post' ) );
140
  // Cron job hook
141
  add_action( 'ai1ec_cron', array( &$ai1ec_importer_controller, 'cron' ) );
142
  // Notification cron job hook
143
- add_action( 'ai1ec_n_cron', array( &$ai1ec_exporter_controller, 'n_cron' ) );
144
  // Category colors
145
- add_action( 'events_categories_add_form_fields', array( &$ai1ec_events_controller, 'events_categories_add_form_fields' ) );
146
- add_action( 'events_categories_edit_form_fields', array( &$ai1ec_events_controller, 'events_categories_edit_form_fields' ) );
147
- add_action( 'created_events_categories', array( &$ai1ec_events_controller, 'created_events_categories' ) );
148
- add_action( 'edited_events_categories', array( &$ai1ec_events_controller, 'edited_events_categories' ) );
149
- add_action( 'admin_notices', array( &$ai1ec_app_helper, 'admin_notices' ) );
150
  // Scripts/styles for settings and widget admin screens.
151
- add_action( 'admin_enqueue_scripts', array( &$ai1ec_app_helper, 'admin_enqueue_scripts' ) );
152
  // Widgets
153
  add_action( 'widgets_init', create_function( '', "return register_widget( 'Ai1ec_Agenda_Widget' );" ) );
154
 
155
  // ===========
156
  // = FILTERS =
157
  // ===========
158
- add_filter( 'posts_orderby', array( &$ai1ec_app_helper, 'orderby' ), 10, 2 );
159
  // add custom column names and change existing columns
160
- add_filter( 'manage_ai1ec_event_posts_columns', array( &$ai1ec_app_helper, 'change_columns' ) );
161
  // filter the post lists by custom filters
162
- add_filter( 'parse_query', array( &$ai1ec_app_helper, 'taxonomy_filter_post_type_request' ) );
163
  // Filter event post content, in single- and multi-post views
164
- add_filter( 'the_content', array( &$ai1ec_events_controller, 'event_content' ), PHP_INT_MAX - 1 );
165
  // Override excerpt filters for proper event display in excerpt form
166
- add_filter( 'get_the_excerpt', array( &$ai1ec_events_controller, 'event_excerpt' ), 11 );
167
- add_filter( 'the_excerpt', array( &$ai1ec_events_controller, 'event_excerpt_noautop' ), 11 );
168
  remove_filter( 'the_excerpt', 'wpautop', 10 );
169
  // Update event post update messages
170
- add_filter( 'post_updated_messages', array( &$ai1ec_events_controller, 'post_updated_messages' ) );
171
  // Sort the custom columns
172
- add_filter( 'manage_edit-ai1ec_event_sortable_columns', array( &$ai1ec_app_helper, 'sortable_columns' ) );
173
- add_filter( 'map_meta_cap', array( &$ai1ec_app_helper, 'map_meta_cap' ), 10, 4 );
174
  // Inject event categories, only in front-end, depending on setting
175
  if( $ai1ec_settings->inject_categories && ! is_admin() ) {
176
- add_filter( 'get_terms', array( &$ai1ec_app_helper, 'inject_categories' ), 10, 3 );
177
- add_filter( 'wp_list_categories', array( &$ai1ec_app_helper, 'selected_category_link' ), 10, 2 );
178
  }
179
  // Rewrite event category URLs to point to calendar page.
180
- add_filter( 'term_link', array( &$ai1ec_app_helper, 'calendar_term_link' ), 10, 3 );
181
  // Add a link to settings page on the plugin list page.
182
- add_filter( 'plugin_action_links_' . AI1EC_PLUGIN_BASENAME, array( &$ai1ec_settings_controller, 'plugin_action_links' ) );
183
  // Add a link to donate page on plugin list page.
184
- add_filter( 'plugin_row_meta', array( &$ai1ec_settings_controller, 'plugin_row_meta' ), 10, 2 );
185
- add_filter( 'post_type_link', array( &$ai1ec_events_helper, 'post_type_link' ), 10, 3 );
186
- add_filter( 'ai1ec_template_root_path', array( &$ai1ec_themes_controller, 'template_root_path' ) );
187
- add_filter( 'ai1ec_template_root_url', array( &$ai1ec_themes_controller, 'template_root_url' ) );
188
 
189
  // ========
190
  // = AJAX =
191
  // ========
192
  // Add iCalendar feed
193
- add_action( 'wp_ajax_ai1ec_add_ics', array( &$ai1ec_settings_controller, 'add_ics_feed' ) );
194
  // Delete iCalendar feed
195
- add_action( 'wp_ajax_ai1ec_delete_ics', array( &$ai1ec_settings_controller, 'delete_ics_feed' ) );
196
  // Flush iCalendar feed
197
- add_action( 'wp_ajax_ai1ec_flush_ics', array( &$ai1ec_settings_controller, 'flush_ics_feed' ) );
198
  // Update iCalendar feed
199
- add_action( 'wp_ajax_ai1ec_update_ics', array( &$ai1ec_settings_controller, 'update_ics_feed' ) );
200
 
201
  // RRule to Text
202
- add_action( 'wp_ajax_ai1ec_rrule_to_text', array( &$ai1ec_events_helper, 'convert_rrule_to_text' ) );
203
 
204
  // Display Repeat Box
205
- add_action( 'wp_ajax_ai1ec_get_repeat_box', array( &$ai1ec_events_helper, 'get_repeat_box' ) );
206
- add_action( 'wp_ajax_ai1ec_get_date_picker_box', array( &$ai1ec_events_helper, 'get_date_picker_box' ) );
207
 
208
  // Disable notifications
209
- add_action( 'wp_ajax_ai1ec_disable_notification', array( &$ai1ec_settings_controller, 'disable_notification' ) );
210
- add_action( 'wp_ajax_ai1ec_disable_intro_video', array( &$ai1ec_settings_controller, 'disable_intro_video' ) );
211
-
212
  // ==============
213
  // = Shortcodes =
214
  // ==============
215
- add_shortcode( 'ai1ec', array( &$ai1ec_events_helper, 'shortcode' ) );
216
 
217
  }
218
 
@@ -239,9 +242,13 @@ class Ai1ec_App_Controller {
239
  * @return void
240
  **/
241
  function load_textdomain() {
242
- if( self::$_load_domain === FALSE ) {
243
- load_plugin_textdomain( AI1EC_PLUGIN_NAME, false, AI1EC_LANGUAGE_PATH );
244
- self::$_load_domain = TRUE;
 
 
 
 
245
  }
246
  }
247
 
@@ -376,27 +383,25 @@ class Ai1ec_App_Controller {
376
  function install_n_cron() {
377
  global $ai1ec_settings;
378
 
379
- // if stats are disabled, cancel the cron
380
- if( $ai1ec_settings->allow_statistics == false ) {
381
- // delete our scheduled crons
382
- wp_clear_scheduled_hook( 'ai1ec_n_cron_version' );
383
 
384
- // remove the cron version
385
- delete_option( 'ai1ec_n_cron_version' );
386
 
387
- // prevent the execution of the code below
388
- return;
 
 
389
  }
390
 
391
- // If existing CRON version is not consistent with current plugin's version,
392
- // or does not exist, then create/update cron using
393
- if( get_option( 'ai1ec_n_cron_version' ) != AI1EC_N_CRON_VERSION ) {
394
- // delete our scheduled crons
395
- wp_clear_scheduled_hook( 'ai1ec_n_cron_version' );
396
  // set the new cron
397
- wp_schedule_event( time(), AI1EC_N_CRON_FREQ, 'ai1ec_n_cron' );
398
  // update the cron version
399
- update_option( 'ai1ec_n_cron_version', AI1EC_N_CRON_VERSION );
400
  }
401
  }
402
 
@@ -451,18 +456,6 @@ class Ai1ec_App_Controller {
451
  // Load our plugin's meta boxes.
452
  add_action( "load-{$ai1ec_settings->settings_page}", array( &$ai1ec_settings_controller, 'add_settings_meta_boxes' ) );
453
 
454
- // ========================
455
- // = Calendar Update Page =
456
- // ========================
457
- add_submenu_page(
458
- 'edit.php?post_type=' . AI1EC_POST_TYPE,
459
- __( 'Upgrade', AI1EC_PLUGIN_NAME ),
460
- __( 'Upgrade', AI1EC_PLUGIN_NAME ),
461
- 'update_plugins',
462
- AI1EC_PLUGIN_NAME . '-upgrade',
463
- array( &$this, 'upgrade' )
464
- );
465
- remove_submenu_page( 'edit.php?post_type=' . AI1EC_POST_TYPE, AI1EC_PLUGIN_NAME . '-upgrade' );
466
  }
467
 
468
  /**
@@ -547,32 +540,5 @@ class Ai1ec_App_Controller {
547
  return $content;
548
  }
549
 
550
- /**
551
- * upgrade function
552
- *
553
- * @return void
554
- **/
555
- function upgrade() {
556
- // continue only if user can update plugins
557
- if ( ! current_user_can( 'update_plugins' ) )
558
- wp_die( __( 'You do not have sufficient permissions to update plugins for this site.' ) );
559
- // use our custom class
560
- $upgrader = new Ai1ec_Updater();
561
- // update the plugin
562
- $upgrader->upgrade( 'all-in-one-event-calendar/all-in-one-event-calendar.php' );
563
- }
564
-
565
- /**
566
- * check_themes function
567
- *
568
- * This function checks if the user is not on install themes page
569
- * and redirects the user to that page
570
- *
571
- * @return void
572
- **/
573
- function check_themes() {
574
- if( ! isset( $_REQUEST["page"] ) || $_REQUEST["page"] != AI1EC_PLUGIN_NAME . '-install-themes' )
575
- wp_redirect( admin_url( AI1EC_INSTALL_THEMES_BASE_URL ) );
576
- }
577
  }
578
  // END class
60
  *
61
  * Default constructor - application initialization
62
  **/
63
+ private function __construct() {
 
64
  global $wpdb,
65
  $ai1ec_app_helper,
66
  $ai1ec_events_controller,
72
  $ai1ec_themes_controller;
73
 
74
  // register_activation_hook
75
+ register_activation_hook(
76
+ AI1EC_PLUGIN_NAME . '/' . AI1EC_PLUGIN_NAME . '.php',
77
+ array( $this, 'activation_hook' )
78
+ );
79
 
80
  // Configure MySQL to operate in GMT time
81
  $wpdb->query( "SET time_zone = '+0:00'" );
92
  // Enable stats collection
93
  $this->install_n_cron();
94
 
95
+ // Continue loading hooks only if themes are installed. Otherwise
96
+ // display a notification on the backend with instructions how to
97
+ // install themes.
98
+ if ( ! $ai1ec_themes_controller->are_themes_available() ) {
99
  // Enables the hidden themes installer page
100
+ add_action( 'admin_menu', array( $ai1ec_themes_controller, 'register_theme_installer' ), 1 );
101
  // Redirects the user to install theme page
102
+ add_action( 'admin_notices', array( $ai1ec_app_helper, 'admin_notices_themes' ) );
103
+ return NULL;
104
  }
105
 
106
  // ===========
107
  // = ACTIONS =
108
  // ===========
109
  // Calendar theme initialization
110
+ add_action( 'after_setup_theme', array( $ai1ec_themes_controller, 'setup_theme' ) );
111
  // Create custom post type
112
+ add_action( 'init', array( $ai1ec_app_helper, 'create_post_type' ) );
113
  // Handle ICS export requests
114
+ add_action( 'init', array( $this, 'parse_standalone_request' ) );
115
  // General initialization
116
+ add_action( 'init', array( $ai1ec_events_controller, 'init' ) );
117
  // Load plugin text domain
118
+ add_action( 'init', array( $this, 'load_textdomain' ) );
119
  // Register The Event Calendar importer
120
+ add_action( 'admin_init', array( $ai1ec_importer_controller, 'register_importer' ) );
121
  // Install admin menu items.
122
+ add_action( 'admin_menu', array( $this, 'admin_menu' ), 9 );
123
  // Enable theme updater page if last version of core themes is older than
124
  // current version.
125
  if ( $ai1ec_themes_controller->are_themes_outdated() ) {
126
+ add_action( 'admin_menu', array( $ai1ec_themes_controller, 'register_theme_updater' ) );
127
  }
128
  // Add Event counts to dashboard.
129
+ add_action( 'right_now_content_table_end', array( $ai1ec_app_helper, 'right_now_content_table_end' ) );
130
  // add content for our custom columns
131
+ add_action( 'manage_posts_custom_column', array( $ai1ec_app_helper, 'custom_columns' ), 10, 2 );
132
  // Add filtering dropdowns for event categories and tags
133
+ add_action( 'restrict_manage_posts', array( $ai1ec_app_helper, 'taxonomy_filter_restrict_manage_posts' ) );
134
  // Trigger display of page in front-end depending on request
135
+ add_action( 'template_redirect', array( $this, 'route_request' ) );
136
  // Add meta boxes to event creation/edit form.
137
+ add_action( 'add_meta_boxes', array( $ai1ec_app_helper, 'add_meta_boxes' ) );
138
+ add_filter( 'screen_layout_columns', array( $ai1ec_app_helper, 'screen_layout_columns' ), 10, 2 );
139
  // Save event data when post is saved
140
+ add_action( 'save_post', array( $ai1ec_events_controller, 'save_post' ), 10, 2 );
141
  // Delete event data when post is deleted
142
+ add_action( 'delete_post', array( $ai1ec_events_controller, 'delete_post' ) );
143
  // Cron job hook
144
  add_action( 'ai1ec_cron', array( &$ai1ec_importer_controller, 'cron' ) );
145
  // Notification cron job hook
146
+ add_action( 'ai1ec_n_cron', array( $ai1ec_exporter_controller, 'n_cron' ) );
147
  // Category colors
148
+ add_action( 'events_categories_add_form_fields', array( $ai1ec_events_controller, 'events_categories_add_form_fields' ) );
149
+ add_action( 'events_categories_edit_form_fields', array( $ai1ec_events_controller, 'events_categories_edit_form_fields' ) );
150
+ add_action( 'created_events_categories', array( $ai1ec_events_controller, 'created_events_categories' ) );
151
+ add_action( 'edited_events_categories', array( $ai1ec_events_controller, 'edited_events_categories' ) );
152
+ add_action( 'admin_notices', array( $ai1ec_app_helper, 'admin_notices' ) );
153
  // Scripts/styles for settings and widget admin screens.
154
+ add_action( 'admin_enqueue_scripts', array( $ai1ec_app_helper, 'admin_enqueue_scripts' ) );
155
  // Widgets
156
  add_action( 'widgets_init', create_function( '', "return register_widget( 'Ai1ec_Agenda_Widget' );" ) );
157
 
158
  // ===========
159
  // = FILTERS =
160
  // ===========
161
+ add_filter( 'posts_orderby', array( $ai1ec_app_helper, 'orderby' ), 10, 2 );
162
  // add custom column names and change existing columns
163
+ add_filter( 'manage_ai1ec_event_posts_columns', array( $ai1ec_app_helper, 'change_columns' ) );
164
  // filter the post lists by custom filters
165
+ add_filter( 'parse_query', array( $ai1ec_app_helper, 'taxonomy_filter_post_type_request' ) );
166
  // Filter event post content, in single- and multi-post views
167
+ add_filter( 'the_content', array( $ai1ec_events_controller, 'event_content' ), PHP_INT_MAX - 1 );
168
  // Override excerpt filters for proper event display in excerpt form
169
+ add_filter( 'get_the_excerpt', array( $ai1ec_events_controller, 'event_excerpt' ), 11 );
170
+ add_filter( 'the_excerpt', array( $ai1ec_events_controller, 'event_excerpt_noautop' ), 11 );
171
  remove_filter( 'the_excerpt', 'wpautop', 10 );
172
  // Update event post update messages
173
+ add_filter( 'post_updated_messages', array( $ai1ec_events_controller, 'post_updated_messages' ) );
174
  // Sort the custom columns
175
+ add_filter( 'manage_edit-ai1ec_event_sortable_columns', array( $ai1ec_app_helper, 'sortable_columns' ) );
176
+ add_filter( 'map_meta_cap', array( $ai1ec_app_helper, 'map_meta_cap' ), 10, 4 );
177
  // Inject event categories, only in front-end, depending on setting
178
  if( $ai1ec_settings->inject_categories && ! is_admin() ) {
179
+ add_filter( 'get_terms', array( $ai1ec_app_helper, 'inject_categories' ), 10, 3 );
180
+ add_filter( 'wp_list_categories', array( $ai1ec_app_helper, 'selected_category_link' ), 10, 2 );
181
  }
182
  // Rewrite event category URLs to point to calendar page.
183
+ add_filter( 'term_link', array( $ai1ec_app_helper, 'calendar_term_link' ), 10, 3 );
184
  // Add a link to settings page on the plugin list page.
185
+ add_filter( 'plugin_action_links_' . AI1EC_PLUGIN_BASENAME, array( $ai1ec_settings_controller, 'plugin_action_links' ) );
186
  // Add a link to donate page on plugin list page.
187
+ add_filter( 'plugin_row_meta', array( $ai1ec_settings_controller, 'plugin_row_meta' ), 10, 2 );
188
+ add_filter( 'post_type_link', array( $ai1ec_events_helper, 'post_type_link' ), 10, 3 );
189
+ add_filter( 'ai1ec_template_root_path', array( $ai1ec_themes_controller, 'template_root_path' ) );
190
+ add_filter( 'ai1ec_template_root_url', array( $ai1ec_themes_controller, 'template_root_url' ) );
191
 
192
  // ========
193
  // = AJAX =
194
  // ========
195
  // Add iCalendar feed
196
+ add_action( 'wp_ajax_ai1ec_add_ics', array( $ai1ec_settings_controller, 'add_ics_feed' ) );
197
  // Delete iCalendar feed
198
+ add_action( 'wp_ajax_ai1ec_delete_ics', array( $ai1ec_settings_controller, 'delete_ics_feed' ) );
199
  // Flush iCalendar feed
200
+ add_action( 'wp_ajax_ai1ec_flush_ics', array( $ai1ec_settings_controller, 'flush_ics_feed' ) );
201
  // Update iCalendar feed
202
+ add_action( 'wp_ajax_ai1ec_update_ics', array( $ai1ec_settings_controller, 'update_ics_feed' ) );
203
 
204
  // RRule to Text
205
+ add_action( 'wp_ajax_ai1ec_rrule_to_text', array( $ai1ec_events_helper, 'convert_rrule_to_text' ) );
206
 
207
  // Display Repeat Box
208
+ add_action( 'wp_ajax_ai1ec_get_repeat_box', array( $ai1ec_events_helper, 'get_repeat_box' ) );
209
+ add_action( 'wp_ajax_ai1ec_get_date_picker_box', array( $ai1ec_events_helper, 'get_date_picker_box' ) );
210
 
211
  // Disable notifications
212
+ add_action( 'wp_ajax_ai1ec_disable_notification', array( $ai1ec_settings_controller, 'disable_notification' ) );
213
+ add_action( 'wp_ajax_ai1ec_disable_intro_video', array( $ai1ec_settings_controller, 'disable_intro_video' ) );
214
+ add_action( 'wp_ajax_ai1ec_disable_standard_notice', array( $ai1ec_settings_controller, 'disable_standard_notice' ) );
215
  // ==============
216
  // = Shortcodes =
217
  // ==============
218
+ add_shortcode( 'ai1ec', array( $ai1ec_events_helper, 'shortcode' ) );
219
 
220
  }
221
 
242
  * @return void
243
  **/
244
  function load_textdomain() {
245
+ if ( false === self::$_load_domain ) {
246
+ load_plugin_textdomain(
247
+ AI1EC_PLUGIN_NAME,
248
+ false,
249
+ AI1EC_LANGUAGE_PATH
250
+ );
251
+ self::$_load_domain = true;
252
  }
253
  }
254
 
383
  function install_n_cron() {
384
  global $ai1ec_settings;
385
 
386
+ $hook_name = 'ai1ec_n_cron';
387
+ $optn_name = $hook_name . '_version';
 
 
388
 
389
+ // delete our scheduled crons
390
+ wp_clear_scheduled_hook( $hook_name );
391
 
392
+ // if stats are disabled, cancel the cron
393
+ if ( ! $ai1ec_settings->allow_statistics ) {
394
+ delete_option( $optn_name ); // remove the cron version
395
+ return NULL; // prevent the execution of the code below
396
  }
397
 
398
+ // If existing CRON version is not consistent with current plugin's
399
+ // version, or does not exist, then create/update cron using
400
+ if ( AI1EC_N_CRON_VERSION != get_option( $optn_name ) ) {
 
 
401
  // set the new cron
402
+ wp_schedule_event( time(), AI1EC_N_CRON_FREQ, $hook_name );
403
  // update the cron version
404
+ update_option( $optn_name, AI1EC_N_CRON_VERSION );
405
  }
406
  }
407
 
456
  // Load our plugin's meta boxes.
457
  add_action( "load-{$ai1ec_settings->settings_page}", array( &$ai1ec_settings_controller, 'add_settings_meta_boxes' ) );
458
 
 
 
 
 
 
 
 
 
 
 
 
 
459
  }
460
 
461
  /**
540
  return $content;
541
  }
542
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
543
  }
544
  // END class
app/controller/class-ai1ec-settings-controller.php CHANGED
@@ -286,6 +286,22 @@ class Ai1ec_Settings_Controller {
286
  $ai1ec_view_helper->json_response( $output );
287
  }
288
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
  /**
290
  * Disable intro video (AJAX callback).
291
  *
286
  $ai1ec_view_helper->json_response( $output );
287
  }
288
 
289
+ /**
290
+ * Disable standard notification (AJAX callback).
291
+ *
292
+ * @return void
293
+ **/
294
+ function disable_standard_notice() {
295
+ global $ai1ec_view_helper, $ai1ec_settings;
296
+
297
+ $ai1ec_settings->update_standard_notification( false );
298
+ $output = array(
299
+ 'error' => false,
300
+ 'message' => 'Request successful.'
301
+ );
302
+
303
+ $ai1ec_view_helper->json_response( $output );
304
+ }
305
  /**
306
  * Disable intro video (AJAX callback).
307
  *
app/controller/class-ai1ec-themes-controller.php CHANGED
@@ -93,17 +93,17 @@ class Ai1ec_Themes_Controller {
93
  }
94
 
95
  /**
96
- * are_themes_available function
97
  *
98
- * Checks if core calendar theme folder is present in wp-content.
99
- *
100
- * @return bool
101
- **/
102
  public function are_themes_available() {
103
- // Are calendar themes folder and Vortex theme present under wp-content ?
104
- if( @is_dir( AI1EC_THEMES_ROOT ) === true && @is_dir( AI1EC_DEFAULT_THEME_PATH ) === true )
 
 
105
  return true;
106
-
107
  return false;
108
  }
109
 
@@ -111,17 +111,20 @@ class Ai1ec_Themes_Controller {
111
  * Register Install Calendar Themes page in wp-admin.
112
  */
113
  function register_theme_installer() {
114
- // Add menu item for theme install page, but remove it using remove_submenu_page
115
- // to generate a "ghost" page
116
  add_submenu_page(
117
  'themes.php',
118
  __( 'Install Calendar Themes', AI1EC_PLUGIN_NAME ),
119
  __( 'Install Calendar Themes', AI1EC_PLUGIN_NAME ),
120
  'install_themes',
121
  AI1EC_PLUGIN_NAME . '-install-themes',
122
- array( &$this, 'install_themes' )
 
 
 
 
123
  );
124
- remove_submenu_page( 'themes.php', AI1EC_PLUGIN_NAME . '-install-themes' );
125
  }
126
 
127
  /**
93
  }
94
 
95
  /**
96
+ * Check if core calendar theme folder is present in wp-content/ directory
97
  *
98
+ * @return bool Existence
99
+ */
 
 
100
  public function are_themes_available() {
101
+ if (
102
+ true === @is_dir( AI1EC_THEMES_ROOT ) &&
103
+ true === @is_dir( AI1EC_DEFAULT_THEME_PATH )
104
+ ) {
105
  return true;
106
+ }
107
  return false;
108
  }
109
 
111
  * Register Install Calendar Themes page in wp-admin.
112
  */
113
  function register_theme_installer() {
114
+ // Add menu item for theme install page, but remove it using
115
+ // `remove_submenu_page()` to generate a "ghost" page
116
  add_submenu_page(
117
  'themes.php',
118
  __( 'Install Calendar Themes', AI1EC_PLUGIN_NAME ),
119
  __( 'Install Calendar Themes', AI1EC_PLUGIN_NAME ),
120
  'install_themes',
121
  AI1EC_PLUGIN_NAME . '-install-themes',
122
+ array( $this, 'install_themes' )
123
+ );
124
+ remove_submenu_page(
125
+ 'themes.php',
126
+ AI1EC_PLUGIN_NAME . '-install-themes'
127
  );
 
128
  }
129
 
130
  /**
app/helper/class-ai1ec-app-helper.php CHANGED
@@ -670,38 +670,153 @@ class Ai1ec_App_Helper {
670
  return $output;
671
  }
672
 
673
- /**
674
- * admin_notices function
675
- *
676
- * Notify the user about anything special.
677
- *
678
- * @return void
679
- **/
680
- function admin_notices() {
681
- global $ai1ec_view_helper,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
682
  $ai1ec_settings,
683
  $plugin_page,
684
  $ai1ec_themes_controller;
685
 
686
- // Display Lite version unsupported notice.
687
- $args = array(
688
- 'msg' => '<p class="timely ai1ec-upgrade-notice"><span><strong>' .
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
689
  __( 'All-in-One Event Calendar Notice', AI1EC_PLUGIN_NAME ) .
690
  ':</strong> ' .
691
- __( 'You are using the <strong>Lite</strong> Calendar. This edition of the plugin is no longer supported.', AI1EC_PLUGIN_NAME ) .
692
  '</span> <a href="' .
693
- esc_attr( admin_url( 'edit.php?post_type=' . AI1EC_POST_TYPE . '&page=' . AI1EC_PLUGIN_NAME . '-upgrade' ) ) .
694
- '" class="btn btn-primary">' .
695
- __( 'Upgrade to the <span><strong>Standard</strong> Calendar</span> for free', AI1EC_PLUGIN_NAME ) .
696
- '</a></p>',
697
- );
698
- $ai1ec_view_helper->display_admin( 'admin_notices.php', $args );
 
 
 
 
 
 
 
 
 
 
699
 
700
  // Display introductory video notice if not disabled.
701
- if( $ai1ec_settings->show_intro_video ) {
702
  $args = array(
703
- 'label' => __( 'Welcome to the All-in-One Event Calendar, by Timely', AI1EC_PLUGIN_NAME ),
704
- 'msg' => sprintf(
705
  '<div class="timely"><a href="#ai1ec-video-modal" data-toggle="modal" ' .
706
  'class="button-primary pull-left">%s</a>' .
707
  '<div class="pull-left">&nbsp;</div></div>',
@@ -714,31 +829,33 @@ class Ai1ec_App_Helper {
714
  );
715
  $ai1ec_view_helper->display_admin( 'admin_notices.php', $args );
716
  $args = array(
717
- 'modal_id' => 'ai1ec-video-modal',
718
  'video_container_id' => 'ai1ec-video',
719
- 'title' => __( 'Introducing the All-in-One Event Calendar, by Timely',
720
- AI1EC_PLUGIN_NAME ),
721
- 'youtube_id' => 'XJ-KHOqBKuQ',
722
- 'footer' => sprintf( '<div style="text-align: center;">' .
 
 
 
723
  '<a class="btn btn-large btn-primary" href="%s">' .
724
  '<i class="timely-icon-arrow-down timely-icon-large"></i> %s</a></div>',
725
- admin_url( 'edit.php?post_type=' . AI1EC_POST_TYPE . '&amp;page=' .
726
- AI1EC_PLUGIN_NAME . '-upgrade' ),
727
- __( 'Upgrade to Premium for Free', AI1EC_PLUGIN_NAME )
728
  ),
729
  // Required CSS and JS may not have has been attached. Let template know
730
  // about it so that it can be dynamically added to <head> (it's now too
731
  // late in the WP bootstrap to add CSS/JS to <head>).
732
- 'css_loaded' => wp_style_is( 'timely-bootstrap' ),
733
- 'css_url' => AI1EC_ADMIN_THEME_CSS_URL . '/bootstrap.min.css',
734
- 'js_loaded' => wp_script_is( 'timely-bootstrap-modal' ),
735
- 'js_url' => AI1EC_ADMIN_THEME_JS_URL . '/bootstrap-modal.js',
736
  );
737
  $ai1ec_view_helper->display_admin( 'video_modal.php', $args );
738
  }
739
 
740
  // No themes available notice.
741
- if( ! $ai1ec_themes_controller->are_themes_available() ) {
742
  $args = array(
743
  'label' => __( 'All-in-One Event Calendar Notice', AI1EC_PLUGIN_NAME ),
744
  'msg' => sprintf(
@@ -760,10 +877,13 @@ class Ai1ec_App_Helper {
760
  }
761
 
762
  // Outdated themes notice (on all pages except update themes page).
763
- if ( $plugin_page != AI1EC_PLUGIN_NAME . '-update-themes' && $ai1ec_themes_controller->are_themes_outdated() ) {
 
 
 
764
  $args = array(
765
  'label' => __( 'All-in-One Event Calendar Notice', AI1EC_PLUGIN_NAME ),
766
- 'msg' => sprintf(
767
  __( '<p><strong>Core calendar files are out of date.</strong> ' .
768
  'We have found updates for some of your core calendar files and you should update them now to ensure proper functioning of your calendar.</p>' .
769
  '<p><strong>Warning:</strong> If you have previously modified any core calendar files, ' .
@@ -775,7 +895,7 @@ class Ai1ec_App_Helper {
775
  $ai1ec_view_helper->display_admin( 'admin_notices.php', $args );
776
  }
777
 
778
- if( $ai1ec_settings->show_data_notification ) {
779
  $args = array(
780
  'label' => __( 'All-in-One Event Calendar Notice', AI1EC_PLUGIN_NAME ),
781
  'msg' =>
@@ -795,54 +915,57 @@ class Ai1ec_App_Helper {
795
  $ai1ec_view_helper->display_admin( 'admin_notices.php', $args );
796
  }
797
 
798
- // If calendar page or time zone has not been set, this is a fresh install.
799
- // Additionally, if we're not already updating the settings, alert user
800
- // appropriately that the calendar is not properly set up.
801
- if( (! $ai1ec_settings->calendar_page_id ||
802
- ! get_option( 'timezone_string' )) &&
803
- ! isset( $_REQUEST['ai1ec_save_settings'] ) ) {
804
- $args = array();
805
- $messages = array();
806
-
807
- // Display messages for blog admin.
808
- if( current_user_can( 'manage_ai1ec_options' ) ) {
809
- // If on the settings page, instruct user as to what to do.
810
- if( $plugin_page == AI1EC_PLUGIN_NAME . '-settings' ) {
811
- if( ! $ai1ec_settings->calendar_page_id ) {
812
- $messages[] = __( 'Select an option in the <strong>Calendar page</strong> dropdown list.', AI1EC_PLUGIN_NAME );
813
- }
814
- if( ! get_option( 'timezone_string' ) ) {
815
- $messages[] = __( 'Select an option in the <strong>Timezone</strong> dropdown list.', AI1EC_PLUGIN_NAME );
816
- }
817
- $messages[] = __( 'Click <strong>Update Settings</strong>.', AI1EC_PLUGIN_NAME );
818
- }
819
- // Else, not on the settings page, so direct user there.
820
- else {
821
- $msg = sprintf(
822
- __( 'The plugin is installed, but has not been configured. <a href="%s">Click here to set it up now &raquo;</a>', AI1EC_PLUGIN_NAME ),
823
- admin_url( AI1EC_SETTINGS_BASE_URL )
824
- );
825
- $messages[] = $msg;
826
- }
827
- }
828
- // Else display messages for other blog users
829
- else {
830
- $messages[] = __( 'The plugin is installed, but has not been configured. Please log in as an Administrator to set it up.', AI1EC_PLUGIN_NAME );
831
- }
832
 
833
- // Format notice message.
834
- if (count($messages) > 1) {
835
- $args['msg'] = __( '<p>To set up the plugin:</p>', AI1EC_PLUGIN_NAME );
836
- $args['msg'] .= '<ol><li>';
837
- $args['msg'] .= implode( '</li><li>', $messages );
838
- $args['msg'] .= '</li></ol>';
839
- }
840
- else {
841
- $args['msg'] = "<p>$messages[0]</p>";
842
- }
843
- $args['label'] = __( 'All-in-One Event Calendar Notice', AI1EC_PLUGIN_NAME );
844
- $ai1ec_view_helper->display_admin( 'admin_notices.php', $args );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
845
  }
 
846
  }
847
 
848
  /**
670
  return $output;
671
  }
672
 
673
+ /**
674
+ * Display notice when themes are unavailable
675
+ *
676
+ * Provide some instructions how to re-install themes.
677
+ *
678
+ * @return void Method doesn't return
679
+ */
680
+ public function admin_notices_themes() {
681
+ if (
682
+ ! $this->_are_notices_available( 2 ) ||
683
+ isset( $_GET['page'] ) &&
684
+ AI1EC_PLUGIN_NAME . '-install-themes' === $_GET['page']
685
+ ) {
686
+ return NULL;
687
+ }
688
+ global $ai1ec_view_helper;
689
+ $args = array(
690
+ 'label' => __( 'All-in-One Event Calendar Notice', AI1EC_PLUGIN_NAME ),
691
+ 'msg' => sprintf(
692
+ __(
693
+ '<p><strong>Core calendar files are not installed.</strong></p>' .
694
+ '<p>Please visit the <a href="%s">Themes Installer page</a> to fix this issue. Until then, the calendar will be unavailable.</p>',
695
+ AI1EC_PLUGIN_NAME
696
+ ),
697
+ admin_url( AI1EC_INSTALL_THEMES_BASE_URL )
698
+ ),
699
+ );
700
+ $ai1ec_view_helper->display_admin( 'admin_notices.php', $args );
701
+ }
702
+
703
+ /**
704
+ * Notify the user about anything special.
705
+ *
706
+ * @return void
707
+ */
708
+ function admin_notices() {
709
+ if ( ! $this->_are_notices_available( 1 ) ) {
710
+ return NULL;
711
+ }
712
+ global $ai1ec_view_helper,
713
  $ai1ec_settings,
714
  $plugin_page,
715
  $ai1ec_themes_controller;
716
 
717
+ // If calendar page or time zone has not been set, this is a fresh install.
718
+ // Additionally, if we're not already updating the settings, alert user
719
+ // appropriately that the calendar is not properly set up.
720
+ if (
721
+ (
722
+ ! $ai1ec_settings->calendar_page_id ||
723
+ ! get_option( 'timezone_string' )
724
+ ) &&
725
+ ! isset( $_REQUEST['ai1ec_save_settings'] )
726
+ ) {
727
+ $args = array();
728
+ $messages = array();
729
+
730
+ // Display messages for blog admin.
731
+ if ( current_user_can( 'manage_ai1ec_options' ) ) {
732
+ // If on the settings page, instruct user as to what to do.
733
+ if ( $plugin_page == AI1EC_PLUGIN_NAME . '-settings' ) {
734
+ if ( ! $ai1ec_settings->calendar_page_id ) {
735
+ $messages[] = __(
736
+ 'Select an option in the <strong>Calendar page</strong> dropdown list.',
737
+ AI1EC_PLUGIN_NAME
738
+ );
739
+ }
740
+ if ( ! get_option( 'timezone_string' ) ) {
741
+ $messages[] = __(
742
+ 'Select an option in the <strong>Timezone</strong> dropdown list.',
743
+ AI1EC_PLUGIN_NAME
744
+ );
745
+ }
746
+ $messages[] = __(
747
+ 'Click <strong>Update Settings</strong>.',
748
+ AI1EC_PLUGIN_NAME
749
+ );
750
+ } else { // Else, not on the settings page, so direct user there.
751
+ $msg = sprintf(
752
+ __(
753
+ 'The plugin is installed, but has not been configured. <a href="%s">Click here to set it up now &raquo;</a>',
754
+ AI1EC_PLUGIN_NAME
755
+ ),
756
+ admin_url( AI1EC_SETTINGS_BASE_URL )
757
+ );
758
+ $messages[] = $msg;
759
+ }
760
+ } else { // Else display messages for other blog users
761
+ $messages[] = __(
762
+ 'The plugin is installed, but has not been configured. Please log in as an Administrator to set it up.',
763
+ AI1EC_PLUGIN_NAME
764
+ );
765
+ }
766
+
767
+ // Format notice message.
768
+ if ( count($messages) > 1 ) {
769
+ $args['msg'] = __(
770
+ '<p>To set up the plugin:</p>',
771
+ AI1EC_PLUGIN_NAME
772
+ );
773
+ $args['msg'] .= '<ol><li>';
774
+ $args['msg'] .= implode( '</li><li>', $messages );
775
+ $args['msg'] .= '</li></ol>';
776
+ } else {
777
+ $args['msg'] = '<p>' . $messages[0] . '</p>';
778
+ }
779
+ $args['label'] = __(
780
+ 'All-in-One Event Calendar Notice',
781
+ AI1EC_PLUGIN_NAME
782
+ );
783
+ $ai1ec_view_helper->display_admin( 'admin_notices.php', $args );
784
+ }
785
+
786
+ if ( ! $this->_are_notices_available( 0 ) ) {
787
+ return NULL;
788
+ }
789
+
790
+ if ( $ai1ec_settings->show_standard_notice ) {
791
+ // Display Lite version unsupported notice.
792
+ $args = array(
793
+ 'msg' => '<p class="timely ai1ec-upgrade-notice"><span><strong>' .
794
  __( 'All-in-One Event Calendar Notice', AI1EC_PLUGIN_NAME ) .
795
  ':</strong> ' .
796
+ __( 'You are using the <strong>"Lite"</strong> Timely calendar. Visit ', AI1EC_PLUGIN_NAME ) .
797
  '</span> <a href="' .
798
+ esc_attr( "http://time.ly" ) .
799
+ '" target="_BLANK">' .
800
+ __( '<span><strong>our website</strong></span>', AI1EC_PLUGIN_NAME ) .
801
+ '</a> and follow ' .
802
+ '<a href=" ' .
803
+ esc_attr( 'http://support.time.ly/difference-lite-standard-versions/' ) .
804
+ '" target="_BLANK">' .
805
+ __( '<span><strong>this guide</strong></span>', AI1EC_PLUGIN_NAME ) .
806
+ '</a> to upgrade to the free "Standard" version with additional features.',
807
+ 'button' => (object) array(
808
+ 'class' => 'ai1ec-dismiss-standard-notification',
809
+ 'value' => __( 'Dismiss', AI1EC_PLUGIN_NAME ),
810
+ ),
811
+ );
812
+ $ai1ec_view_helper->display_admin( 'admin_notices.php', $args );
813
+ }
814
 
815
  // Display introductory video notice if not disabled.
816
+ if ( $ai1ec_settings->show_intro_video ) {
817
  $args = array(
818
+ 'label' => __( 'Welcome to the All-in-One Event Calendar, by Timely', AI1EC_PLUGIN_NAME ),
819
+ 'msg' => sprintf(
820
  '<div class="timely"><a href="#ai1ec-video-modal" data-toggle="modal" ' .
821
  'class="button-primary pull-left">%s</a>' .
822
  '<div class="pull-left">&nbsp;</div></div>',
829
  );
830
  $ai1ec_view_helper->display_admin( 'admin_notices.php', $args );
831
  $args = array(
832
+ 'modal_id' => 'ai1ec-video-modal',
833
  'video_container_id' => 'ai1ec-video',
834
+ 'title' => __(
835
+ 'Introducing the All-in-One Event Calendar, by Timely',
836
+ AI1EC_PLUGIN_NAME
837
+ ),
838
+ 'youtube_id' => 'XJ-KHOqBKuQ',
839
+ 'footer' => sprintf(
840
+ '<div style="text-align: center;">' .
841
  '<a class="btn btn-large btn-primary" href="%s">' .
842
  '<i class="timely-icon-arrow-down timely-icon-large"></i> %s</a></div>',
843
+ 'http://support.time.ly/manually-upgrading-the-calendar/',
844
+ __( 'Upgrade to Standard for Free', AI1EC_PLUGIN_NAME )
 
845
  ),
846
  // Required CSS and JS may not have has been attached. Let template know
847
  // about it so that it can be dynamically added to <head> (it's now too
848
  // late in the WP bootstrap to add CSS/JS to <head>).
849
+ 'css_loaded' => wp_style_is( 'timely-bootstrap' ),
850
+ 'css_url' => AI1EC_ADMIN_THEME_CSS_URL . '/bootstrap.min.css',
851
+ 'js_loaded' => wp_script_is( 'timely-bootstrap-modal' ),
852
+ 'js_url' => AI1EC_ADMIN_THEME_JS_URL . '/bootstrap-modal.js',
853
  );
854
  $ai1ec_view_helper->display_admin( 'video_modal.php', $args );
855
  }
856
 
857
  // No themes available notice.
858
+ if ( ! $ai1ec_themes_controller->are_themes_available() ) {
859
  $args = array(
860
  'label' => __( 'All-in-One Event Calendar Notice', AI1EC_PLUGIN_NAME ),
861
  'msg' => sprintf(
877
  }
878
 
879
  // Outdated themes notice (on all pages except update themes page).
880
+ if (
881
+ $plugin_page != AI1EC_PLUGIN_NAME . '-update-themes' &&
882
+ $ai1ec_themes_controller->are_themes_outdated()
883
+ ) {
884
  $args = array(
885
  'label' => __( 'All-in-One Event Calendar Notice', AI1EC_PLUGIN_NAME ),
886
+ 'msg' => sprintf(
887
  __( '<p><strong>Core calendar files are out of date.</strong> ' .
888
  'We have found updates for some of your core calendar files and you should update them now to ensure proper functioning of your calendar.</p>' .
889
  '<p><strong>Warning:</strong> If you have previously modified any core calendar files, ' .
895
  $ai1ec_view_helper->display_admin( 'admin_notices.php', $args );
896
  }
897
 
898
+ if ( $ai1ec_settings->show_data_notification ) {
899
  $args = array(
900
  'label' => __( 'All-in-One Event Calendar Notice', AI1EC_PLUGIN_NAME ),
901
  'msg' =>
915
  $ai1ec_view_helper->display_admin( 'admin_notices.php', $args );
916
  }
917
 
918
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
919
 
920
+ /**
921
+ * Check whereas our notices should be displayed on this page.
922
+ *
923
+ * Limits notices to Ai1EC pages and WordPress "Plugins", "Updates" pages.
924
+ * Important notices are also displayable in WordPress "Dashboard".
925
+ * Levels of importance (see $importance) are as following:
926
+ * - 0 - messages limited to Ai1EC pages;
927
+ * - 1 - messages limited to [0] and Plugins/Updates pages;
928
+ * - 2 - messages limited to [1] and Dashboard.
929
+ *
930
+ * @param int $importance The level of importance. See above for details.
931
+ *
932
+ * @return bool Availability
933
+ */
934
+ protected function _are_notices_available( $importance = 0 ) {
935
+ // In CRON `get_current_screen()` is not present
936
+ // and we wish to have notice on all "our" pages
937
+ if (
938
+ isset( $_GET['page'] ) &&
939
+ 0 === strncasecmp(
940
+ $_GET['page'],
941
+ AI1EC_PLUGIN_NAME,
942
+ strlen( AI1EC_PLUGIN_NAME )
943
+ ) ||
944
+ isset( $_GET['post_type'] ) &&
945
+ AI1EC_POST_TYPE === $_GET['post_type'] ||
946
+ ! function_exists( 'get_current_screen' )
947
+ ) {
948
+ return true;
949
+ }
950
+ if ( $importance < 1 ) {
951
+ return false;
952
+ }
953
+ $screen = get_current_screen();
954
+ $allow_on = array(
955
+ 'plugins',
956
+ 'update-core',
957
+ );
958
+ if ( $importance > 1 ) {
959
+ $allow_on[] = 'dashboard';
960
+ }
961
+ if (
962
+ is_object( $screen ) &&
963
+ isset( $screen->id ) &&
964
+ in_array( $screen->id, $allow_on )
965
+ ) {
966
+ return true;
967
  }
968
+ return false;
969
  }
970
 
971
  /**
app/helper/class-ai1ec-events-helper.php CHANGED
@@ -122,6 +122,76 @@ class Ai1ec_Events_Helper {
122
  $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE post_id = %d", $pid ) );
123
  }
124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  /**
126
  * cache_event function
127
  *
@@ -132,110 +202,120 @@ class Ai1ec_Events_Helper {
132
  * @param object $event Event to generate cache table for
133
  *
134
  * @return void
135
- **/
136
- function cache_event( &$event ) {
137
  global $wpdb;
138
 
139
- // Convert event's timestamps to local for correct calculations of
140
  // recurrence. Need to also remove PHP timezone offset for each date for
141
  // SG_iCal to calculate correct recurring instances.
142
- $event->start = $this->gmt_to_local( $event->start ) - date( 'Z', $event->start );
143
- $event->end = $this->gmt_to_local( $event->end ) - date( 'Z', $event->end );
 
 
144
 
145
  $evs = array();
146
  $e = array(
147
  'post_id' => $event->post_id,
148
- 'start' => $event->start,
149
- 'end' => $event->end,
150
  );
151
  $duration = $event->getDuration();
152
 
153
- // Timestamp of today's date + 10 years
154
- $tif = gmmktime() + 315569260; //315 569 260 = 10 years in seconds
155
  // Always cache initial instance
156
  $evs[] = $e;
157
 
158
  $_start = $event->start;
159
  $_end = $event->end;
160
 
161
- if( $event->recurrence_rules )
162
- {
163
- $count = 0;
164
  $start = $event->start;
165
- $exrule = array();
166
- if( $event->exception_rules ) {
167
- $exrule = $this->generate_dates_array_from_ics_rule( $start, $event->exception_rules );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  }
169
- $freq = $event->getFrequency( $exrule );
170
-
171
- $freq->firstOccurrence();
172
- while( ( $next = $freq->nextOccurrence( $start ) ) > 0 && $count < 1000 )
173
- {
174
- $count++;
175
- $start = $next;
176
- $e['start'] = $start;
177
- $e['end'] = $start + $duration;
 
 
 
 
 
 
 
 
178
  $excluded = false;
179
 
180
- // if event's start date is 10 years in the future, stop the cache at this point
181
- if( $start > $tif ) break;
182
 
183
  // Check if exception dates match this occurence
184
  if( $event->exception_dates ) {
185
- if( $this->date_match_exdates( $start, $event->exception_dates ) )
186
  $excluded = true;
187
  }
188
 
189
  // Add event only if it is not excluded
190
- if( $excluded == false )
191
  $evs[] = $e;
 
192
  }
193
  }
194
 
195
  // Make entries unique (sometimes recurrence generator creates duplicates?)
196
  $evs_unique = array();
197
- foreach( $evs as $ev ) {
198
- $evs_unique[ md5( serialize( $ev ) ) ] = $ev;
199
  }
200
 
201
- foreach( $evs_unique as $e )
202
- {
203
  // Find out if this event instance is already accounted for by an
204
  // overriding 'RECURRENCE-ID' of the same iCalendar feed (by comparing the
205
  // UID, start date, recurrence). If so, then do not create duplicate
206
  // instance of event.
 
 
207
  $matching_event_id = $event->ical_uid ?
208
- $this->get_matching_event_id(
209
- $event->ical_uid,
210
- $event->ical_feed_url,
211
- $start = $this->local_to_gmt( $e['start'] ) - date( 'Z', $e['start'] ),
212
- false, // Only search events that don't define recurrence (i.e. only search for RECURRENCE-ID events)
213
- $event->post_id
214
- )
215
- : null;
 
 
216
 
217
  // If no other instance was found
218
- if( is_null( $matching_event_id ) )
219
- {
220
  $start = getdate( $e['start'] );
221
- $end = getdate( $e['end'] );
222
-
223
- /*
224
- // Commented out for now
225
- // If event spans a day and end time is not midnight, or spans more than
226
- // a day, then create instance for each spanning day
227
- if( ( $start['mday'] != $end['mday'] &&
228
- ( $end['hours'] || $end['minutes'] || $end['seconds'] ) )
229
- || $e['end'] - $e['start'] > 60 * 60 * 24 ) {
230
- $this->create_cache_table_entries( $e );
231
- // Else cache single instance of event
232
- } else {
233
- $this->insert_event_in_cache_table( $e );
234
- }
235
- */
236
  $this->insert_event_in_cache_table( $e );
237
  }
238
  }
 
239
  }
240
 
241
  /**
@@ -402,71 +482,6 @@ class Ai1ec_Events_Helper {
402
  return $this->create_select_element( 'ai1ec_repeat', $options, $selected, array( 5 ) );
403
  }
404
 
405
- /**
406
- * Returns an associative array containing the following information:
407
- * string 'repeat' => pattern of repetition ('DAILY', 'WEEKENDS', etc.)
408
- * int 'count' => end after 'count' times
409
- * int 'until' => repeat until date (as UNIX timestamp)
410
- * Elements are null if no such recurrence information is available.
411
- *
412
- * @param Ai1ec_Event Event object to parse recurrence rules of
413
- * @return array Array structured as described above
414
- **/
415
- function parse_recurrence_rules( &$event )
416
- {
417
- $repeat = null;
418
- $count = null;
419
- $until = null;
420
- $end = 0;
421
- if( ! is_null( $event ) ) {
422
- if( strlen( $event->recurrence_rules ) > 0 ) {
423
- $line = new SG_iCal_Line( $event->recurrence_rules );
424
- $rec = new SG_iCal_Recurrence( $line );
425
- switch( $rec->req ) {
426
- case 'DAILY':
427
- $by_day = $rec->getByDay();
428
- if( empty( $by_day ) ) {
429
- $repeat = 'DAILY';
430
- } elseif( $by_day[0] == 'SA+SU' ) {
431
- $repeat = 'WEEKENDS';
432
- } elseif( count( $by_day ) == 5 ) {
433
- $repeat = 'WEEKDAYS';
434
- } else {
435
- foreach( $by_day as $d ) {
436
- $repeat .= $d . '+';
437
- }
438
- $repeat = substr( $repeat, 0, -1 );
439
- }
440
- break;
441
- case 'WEEKLY':
442
- $repeat = 'WEEKLY';
443
- break;
444
- case 'MONTHLY':
445
- $repeat = 'MONTHLY';
446
- break;
447
- case 'YEARLY':
448
- $repeat = 'YEARLY';
449
- break;
450
- }
451
- $count = $rec->getCount();
452
- $until = $rec->getUntil();
453
- if( $until ) {
454
- $until = strtotime( $rec->getUntil() );
455
- $until += date( 'Z', $until ); // Add timezone offset
456
- $end = 2;
457
- } elseif( $count )
458
- $end = 1;
459
- else
460
- $end = 0;
461
- }
462
- }
463
- return array(
464
- 'repeat' => $repeat,
465
- 'count' => $count,
466
- 'until' => $until,
467
- 'end' => $end
468
- );
469
- }
470
 
471
  /**
472
  * Generates and returns "End after X times" input
@@ -1439,24 +1454,24 @@ class Ai1ec_Events_Helper {
1439
  **/
1440
  function rrule_to_text( $rrule = '') {
1441
  $txt = '';
1442
- $rc = new SG_iCal_Recurrence( new SG_iCal_Line( 'RRULE:' . $rrule ) );
1443
- switch( $rc->getFreq() ) {
1444
  case 'DAILY':
1445
- $this->_get_interval( $txt, 'daily', $rc->getInterval() );
1446
  $this->_ending_sentence( $txt, $rc );
1447
  break;
1448
  case 'WEEKLY':
1449
- $this->_get_interval( $txt, 'weekly', $rc->getInterval() );
1450
  $this->_get_sentence_by( $txt, 'weekly', $rc );
1451
  $this->_ending_sentence( $txt, $rc );
1452
  break;
1453
  case 'MONTHLY':
1454
- $this->_get_interval( $txt, 'monthly', $rc->getInterval() );
1455
  $this->_get_sentence_by( $txt, 'monthly', $rc );
1456
  $this->_ending_sentence( $txt, $rc );
1457
  break;
1458
  case 'YEARLY':
1459
- $this->_get_interval( $txt, 'yearly', $rc->getInterval() );
1460
  $this->_get_sentence_by( $txt, 'yearly', $rc );
1461
  $this->_ending_sentence( $txt, $rc );
1462
  break;
@@ -1506,8 +1521,8 @@ class Ai1ec_Events_Helper {
1506
  * @return void
1507
  **/
1508
  private function ics_rule_to( $rule, $to_gmt = false ) {
1509
- $rc = new SG_iCal_Recurrence( new SG_iCal_Line( 'RRULE:' . $rule ) );
1510
- if( $until = $rc->getUntil() ) {
1511
  if( ! is_int( $until ) ) {
1512
  $until = strtotime( $until );
1513
  }
@@ -1592,13 +1607,13 @@ class Ai1ec_Events_Helper {
1592
 
1593
  switch( $freq ) {
1594
  case 'weekly':
1595
- if( $rc->getByDay() ) {
1596
- if( count( $rc->getByDay() ) > 1 ) {
1597
  // if there are more than 3 days
1598
  // use days's abbr
1599
- if( count( $rc->getByDay() ) > 2 ) {
1600
  $_days = '';
1601
- foreach( $rc->getByDay() as $d ) {
1602
  $day = $this->get_weekday_by_id( $d, true );
1603
  $_days .= ' ' . $wp_locale->weekday_abbrev[$wp_locale->weekday[$day]] . ',';
1604
  }
@@ -1607,7 +1622,7 @@ class Ai1ec_Events_Helper {
1607
  $txt .= ' ' . _x( 'on', 'Recurrence editor - weekly tab', AI1EC_PLUGIN_NAME ) . $_days;
1608
  } else {
1609
  $_days = '';
1610
- foreach( $rc->getByDay() as $d ) {
1611
  $day = $this->get_weekday_by_id( $d, true );
1612
  $_days .= ' ' . $wp_locale->weekday[$day] . ' ' . __( 'and', AI1EC_PLUGIN_NAME );
1613
  }
@@ -1617,7 +1632,7 @@ class Ai1ec_Events_Helper {
1617
  }
1618
  } else {
1619
  $_days = '';
1620
- foreach( $rc->getByDay() as $d ) {
1621
  $day = $this->get_weekday_by_id( $d, true );
1622
  $_days .= ' ' . $wp_locale->weekday[$day];
1623
  }
@@ -1626,32 +1641,32 @@ class Ai1ec_Events_Helper {
1626
  }
1627
  break;
1628
  case 'monthly':
1629
- if( $rc->getByMonthDay() ) {
1630
  // if there are more than 2 days
1631
- if( count( $rc->getByMonthDay() ) > 2 ) {
1632
  $_days = '';
1633
- foreach( $rc->getByMonthDay() as $m_day ) {
1634
  $_days .= ' ' . $this->_ordinal( $m_day ) . ',';
1635
  }
1636
  $_days = substr( $_days, 0, -1 );
1637
  $txt .= ' ' . _x( 'on', 'Recurrence editor - monthly tab', AI1EC_PLUGIN_NAME ) . $_days . ' ' . __( 'of the month', AI1EC_PLUGIN_NAME );
1638
- } else if( count( $rc->getByMonthDay() ) > 1 ) {
1639
  $_days = '';
1640
- foreach( $rc->getByMonthDay() as $m_day ) {
1641
  $_days .= ' ' . $this->_ordinal( $m_day ) . ' ' . __( 'and', AI1EC_PLUGIN_NAME );
1642
  }
1643
  $_days = substr( $_days, 0, -4 );
1644
  $txt .= ' ' . _x( 'on', 'Recurrence editor - monthly tab', AI1EC_PLUGIN_NAME ) . $_days . ' ' . __( 'of the month', AI1EC_PLUGIN_NAME );
1645
  } else {
1646
  $_days = '';
1647
- foreach( $rc->getByMonthDay() as $m_day ) {
1648
  $_days .= ' ' . $this->_ordinal( $m_day );
1649
  }
1650
  $txt .= ' ' . _x( 'on', 'Recurrence editor - monthly tab', AI1EC_PLUGIN_NAME ) . $_days . ' ' . __( 'of the month', AI1EC_PLUGIN_NAME );
1651
  }
1652
- } elseif( $rc->getByDay() ) {
1653
  $_days = '';
1654
- foreach( $rc->getByDay() as $d ) {
1655
  $_dnum = substr( $d, 0, 1);
1656
  $_day = substr( $d, 1, 3 );
1657
  $dnum = ' ' . date_i18n( "jS", strtotime( $_dnum . '-01-1998 12:00:00' ) );
@@ -1662,19 +1677,19 @@ class Ai1ec_Events_Helper {
1662
  }
1663
  break;
1664
  case 'yearly':
1665
- if( $rc->getByMonth() ) {
1666
  // if there are more than 2 months
1667
- if( count( $rc->getByMonth() ) > 2 ) {
1668
  $_months = '';
1669
- foreach( $rc->getByMonth() as $_m ) {
1670
  $_m = $_m < 10 ? 0 . $_m : $_m;
1671
  $_months .= ' ' . $wp_locale->month_abbrev[$wp_locale->month[$_m]] . ',';
1672
  }
1673
  $_months = substr( $_months, 0, -1 );
1674
  $txt .= ' ' . _x( 'on', 'Recurrence editor - yearly tab', AI1EC_PLUGIN_NAME ) . $_months;
1675
- } else if( count( $rc->getByMonth() ) > 1 ) {
1676
  $_months = '';
1677
- foreach( $rc->getByMonth() as $_m ) {
1678
  $_m = $_m < 10 ? 0 . $_m : $_m;
1679
  $_months .= ' ' . $wp_locale->month[$_m] . ' ' . __( 'and', AI1EC_PLUGIN_NAME );
1680
  }
@@ -1682,7 +1697,7 @@ class Ai1ec_Events_Helper {
1682
  $txt .= ' ' . _x( 'on', 'Recurrence editor - yearly tab', AI1EC_PLUGIN_NAME ) . $_months;
1683
  } else {
1684
  $_months = '';
1685
- foreach( $rc->getByMonth() as $_m ) {
1686
  $_m = $_m < 10 ? 0 . $_m : $_m;
1687
  $_months .= ' ' . $wp_locale->month[$_m];
1688
  }
@@ -1783,12 +1798,12 @@ class Ai1ec_Events_Helper {
1783
  * @return void
1784
  **/
1785
  function _ending_sentence( &$txt, &$rc ) {
1786
- if( $until = $rc->getUntil() ) {
1787
  if( ! is_int( $until ) )
1788
  $until = strtotime( $until );
1789
  $txt .= ' ' . sprintf( __( 'until %s', AI1EC_PLUGIN_NAME ), date_i18n( get_option( 'date_format' ), $until, true ) );
1790
  }
1791
- else if( $count = $rc->getCount() )
1792
  $txt .= ' ' . sprintf( __( 'for %d occurrences', AI1EC_PLUGIN_NAME ), $count );
1793
  else
1794
  $txt .= ' - ' . __( 'forever', AI1EC_PLUGIN_NAME );
@@ -1873,12 +1888,12 @@ class Ai1ec_Events_Helper {
1873
  $rule = empty( $event->exception_rules ) ? '' : $event->exception_rules;
1874
  }
1875
 
1876
- $rc = new SG_iCal_Recurrence( new SG_iCal_Line( 'RRULE:' . $rule ) );
1877
 
1878
- if( $until = $rc->getUntil() ) {
1879
  $until = ( is_numeric( $until ) ) ? $until : strtotime( $until );
1880
  }
1881
- else if( $count = $rc->getCount() ) {
1882
  $count = ( is_numeric( $count ) ) ? $count : 100;
1883
  }
1884
  } catch( Ai1ec_Event_Not_Found $e ) { /* event wasn't found, keep defaults */ }
122
  $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE post_id = %d", $pid ) );
123
  }
124
 
125
+ /**
126
+ * when using BYday you need an array of arrays.
127
+ * This function create valid arrays that keep into account the presence
128
+ * of a week number beofre the day
129
+ *
130
+ * @param string $val
131
+ *
132
+ * @return array
133
+ */
134
+ private function create_byday_array( $val ) {
135
+ $week = substr( $val, 0, 1 );
136
+ if ( is_numeric( $week ) ) {
137
+ return array( $week, 'DAY' => substr( $val, 1 ) );
138
+ }
139
+ return array( 'DAY' => $val );
140
+ }
141
+
142
+ /**
143
+ * Parse a `recurrence rule' into an array that can be used to calculate
144
+ * recurrence instances.
145
+ *
146
+ * @see http://kigkonsult.se/iCalcreator/docs/using.html#EXRULE
147
+ *
148
+ * @param string $rule
149
+ * @return array
150
+ */
151
+ private function build_recurrence_rules_array( $rule ) {
152
+ $rules = array();
153
+ $rule_list = explode( ';', $rule );
154
+ foreach ( $rule_list as $single_rule ) {
155
+ if ( false === strpos( $single_rule, '=' ) ) {
156
+ continue;
157
+ }
158
+ list( $key, $val ) = explode( '=', $single_rule );
159
+ $key = strtoupper( $key );
160
+ switch ( $key ) {
161
+ case 'BYDAY':
162
+ $rules['BYDAY'] = array();
163
+ foreach ( explode( ',', $val ) as $day ) {
164
+ $rule_map = $this->create_byday_array( $day );
165
+ $rules['BYDAY'][] = $rule_map;
166
+ if (
167
+ preg_match( '/FREQ=(MONTH|YEAR)LY/i', $rule ) &&
168
+ 1 === count( $rule_map )
169
+ ) {
170
+ // monthly/yearly "last" recurrences need day name
171
+ $rules['BYDAY']['DAY'] = substr(
172
+ $rule_map['DAY'],
173
+ -2
174
+ );
175
+ }
176
+ }
177
+ break;
178
+
179
+ case 'BYMONTHDAY':
180
+ case 'BYMONTH':
181
+ if ( false === strpos( $val, ',' ) ) {
182
+ $rules[$key] = $val;
183
+ } else {
184
+ $rules[$key] = explode( ',', $val );
185
+ }
186
+ break;
187
+
188
+ default:
189
+ $rules[$key] = $val;
190
+ }
191
+ }
192
+ return $rules;
193
+ }
194
+
195
  /**
196
  * cache_event function
197
  *
202
  * @param object $event Event to generate cache table for
203
  *
204
  * @return void
205
+ */
206
+ public function cache_event( $event ) {
207
  global $wpdb;
208
 
209
+ // Convert event timestamps to local for correct calculations of
210
  // recurrence. Need to also remove PHP timezone offset for each date for
211
  // SG_iCal to calculate correct recurring instances.
212
+ $event->start = $this->gmt_to_local( $event->start )
213
+ - date( 'Z', $event->start );
214
+ $event->end = $this->gmt_to_local( $event->end )
215
+ - date( 'Z', $event->end );
216
 
217
  $evs = array();
218
  $e = array(
219
  'post_id' => $event->post_id,
220
+ 'start' => $event->start,
221
+ 'end' => $event->end,
222
  );
223
  $duration = $event->getDuration();
224
 
225
+ // Timestamp of today date + 3 years (94608000 seconds)
226
+ $tif = gmmktime() + 94608000;
227
  // Always cache initial instance
228
  $evs[] = $e;
229
 
230
  $_start = $event->start;
231
  $_end = $event->end;
232
 
233
+ if ( $event->recurrence_rules ) {
 
 
234
  $start = $event->start;
235
+ $wdate = $startdate = iCalUtilityFunctions::_timestamp2date( $_start, 6 );
236
+ $enddate = iCalUtilityFunctions::_timestamp2date( $tif, 6 );
237
+ $exclude_dates = array();
238
+ $recurrence_dates = array();
239
+ if ( $event->exception_rules ) {
240
+ // creat an array for the rules
241
+ $exception_rules = $this->build_recurrence_rules_array( $event->exception_rules );
242
+ $exception_rules = iCalUtilityFunctions::_setRexrule( $exception_rules );
243
+ $result = array();
244
+ // The first array is the result and it is passed by reference
245
+ iCalUtilityFunctions::_recur2date(
246
+ $exclude_dates,
247
+ $exception_rules,
248
+ $wdate,
249
+ $startdate,
250
+ $enddate
251
+ );
252
  }
253
+ $recurrence_rules = $this->build_recurrence_rules_array( $event->recurrence_rules );
254
+ $recurrence_rules = iCalUtilityFunctions::_setRexrule( $recurrence_rules );
255
+ iCalUtilityFunctions::_recur2date(
256
+ $recurrence_dates,
257
+ $recurrence_rules,
258
+ $wdate,
259
+ $startdate,
260
+ $enddate
261
+ );
262
+ // Add the instances
263
+ foreach ( $recurrence_dates as $date => $bool ) {
264
+ // The arrays are in the form timestamp => true so an isset call is what we need
265
+ if( isset( $exclude_dates[$date] ) ) {
266
+ continue;
267
+ }
268
+ $e['start'] = $date;
269
+ $e['end'] = $date + $duration;
270
  $excluded = false;
271
 
 
 
272
 
273
  // Check if exception dates match this occurence
274
  if( $event->exception_dates ) {
275
+ if( $this->date_match_exdates( $date, $event->exception_dates ) )
276
  $excluded = true;
277
  }
278
 
279
  // Add event only if it is not excluded
280
+ if ( $excluded == false ) {
281
  $evs[] = $e;
282
+ }
283
  }
284
  }
285
 
286
  // Make entries unique (sometimes recurrence generator creates duplicates?)
287
  $evs_unique = array();
288
+ foreach ( $evs as $ev ) {
289
+ $evs_unique[md5( serialize( $ev ) )] = $ev;
290
  }
291
 
292
+ foreach ( $evs_unique as $e ) {
 
293
  // Find out if this event instance is already accounted for by an
294
  // overriding 'RECURRENCE-ID' of the same iCalendar feed (by comparing the
295
  // UID, start date, recurrence). If so, then do not create duplicate
296
  // instance of event.
297
+ $start = $this->local_to_gmt( $e['start'] )
298
+ - date( 'Z', $e['start'] );
299
  $matching_event_id = $event->ical_uid ?
300
+ $this->get_matching_event_id(
301
+ $event->ical_uid,
302
+ $event->ical_feed_url,
303
+ $start,
304
+ false, // Only search events that does not define
305
+ // recurrence (i.e. only search for RECURRENCE-ID events)
306
+ $event->post_id
307
+ )
308
+ : NULL;
309
+
310
 
311
  // If no other instance was found
312
+ if ( NULL === $matching_event_id ) {
 
313
  $start = getdate( $e['start'] );
314
+ $end = getdate( $e['end'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  $this->insert_event_in_cache_table( $e );
316
  }
317
  }
318
+
319
  }
320
 
321
  /**
482
  return $this->create_select_element( 'ai1ec_repeat', $options, $selected, array( 5 ) );
483
  }
484
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
485
 
486
  /**
487
  * Generates and returns "End after X times" input
1454
  **/
1455
  function rrule_to_text( $rrule = '') {
1456
  $txt = '';
1457
+ $rc = new Ai1ec_Recurrence_Helper( $rrule );
1458
+ switch( $rc->get_property( 'freq' ) ) {
1459
  case 'DAILY':
1460
+ $this->_get_interval( $txt, 'daily', $rc->get_property( 'interval' ) );
1461
  $this->_ending_sentence( $txt, $rc );
1462
  break;
1463
  case 'WEEKLY':
1464
+ $this->_get_interval( $txt, 'weekly', $rc->get_property( 'interval' ) );
1465
  $this->_get_sentence_by( $txt, 'weekly', $rc );
1466
  $this->_ending_sentence( $txt, $rc );
1467
  break;
1468
  case 'MONTHLY':
1469
+ $this->_get_interval( $txt, 'monthly', $rc->get_property( 'interval' ) );
1470
  $this->_get_sentence_by( $txt, 'monthly', $rc );
1471
  $this->_ending_sentence( $txt, $rc );
1472
  break;
1473
  case 'YEARLY':
1474
+ $this->_get_interval( $txt, 'yearly', $rc->get_property( 'interval' ) );
1475
  $this->_get_sentence_by( $txt, 'yearly', $rc );
1476
  $this->_ending_sentence( $txt, $rc );
1477
  break;
1521
  * @return void
1522
  **/
1523
  private function ics_rule_to( $rule, $to_gmt = false ) {
1524
+ $rc = new Ai1ec_Recurrence_Helper( $rule );
1525
+ if( $until = $rc->get_property( 'until' ) ) {
1526
  if( ! is_int( $until ) ) {
1527
  $until = strtotime( $until );
1528
  }
1607
 
1608
  switch( $freq ) {
1609
  case 'weekly':
1610
+ if( $rc->get_property( 'byday' ) ) {
1611
+ if( count( $rc->get_property( 'byday' ) ) > 1 ) {
1612
  // if there are more than 3 days
1613
  // use days's abbr
1614
+ if( count( $rc->get_property( 'byday' ) ) > 2 ) {
1615
  $_days = '';
1616
+ foreach( $rc->get_property( 'byday' ) as $d ) {
1617
  $day = $this->get_weekday_by_id( $d, true );
1618
  $_days .= ' ' . $wp_locale->weekday_abbrev[$wp_locale->weekday[$day]] . ',';
1619
  }
1622
  $txt .= ' ' . _x( 'on', 'Recurrence editor - weekly tab', AI1EC_PLUGIN_NAME ) . $_days;
1623
  } else {
1624
  $_days = '';
1625
+ foreach( $rc->get_property( 'byday' ) as $d ) {
1626
  $day = $this->get_weekday_by_id( $d, true );
1627
  $_days .= ' ' . $wp_locale->weekday[$day] . ' ' . __( 'and', AI1EC_PLUGIN_NAME );
1628
  }
1632
  }
1633
  } else {
1634
  $_days = '';
1635
+ foreach( $rc->get_property( 'byday' ) as $d ) {
1636
  $day = $this->get_weekday_by_id( $d, true );
1637
  $_days .= ' ' . $wp_locale->weekday[$day];
1638
  }
1641
  }
1642
  break;
1643
  case 'monthly':
1644
+ if( $rc->get_property( 'bymonthday' ) ) {
1645
  // if there are more than 2 days
1646
+ if( count( $rc->get_property( 'bymonthday' ) ) > 2 ) {
1647
  $_days = '';
1648
+ foreach( $rc->get_property( 'bymonthday' ) as $m_day ) {
1649
  $_days .= ' ' . $this->_ordinal( $m_day ) . ',';
1650
  }
1651
  $_days = substr( $_days, 0, -1 );
1652
  $txt .= ' ' . _x( 'on', 'Recurrence editor - monthly tab', AI1EC_PLUGIN_NAME ) . $_days . ' ' . __( 'of the month', AI1EC_PLUGIN_NAME );
1653
+ } else if( count( $rc->get_property( 'bymonthday' ) ) > 1 ) {
1654
  $_days = '';
1655
+ foreach( $rc->get_property( 'bymonthday' ) as $m_day ) {
1656
  $_days .= ' ' . $this->_ordinal( $m_day ) . ' ' . __( 'and', AI1EC_PLUGIN_NAME );
1657
  }
1658
  $_days = substr( $_days, 0, -4 );
1659
  $txt .= ' ' . _x( 'on', 'Recurrence editor - monthly tab', AI1EC_PLUGIN_NAME ) . $_days . ' ' . __( 'of the month', AI1EC_PLUGIN_NAME );
1660
  } else {
1661
  $_days = '';
1662
+ foreach( $rc->get_property( 'bymonthday' ) as $m_day ) {
1663
  $_days .= ' ' . $this->_ordinal( $m_day );
1664
  }
1665
  $txt .= ' ' . _x( 'on', 'Recurrence editor - monthly tab', AI1EC_PLUGIN_NAME ) . $_days . ' ' . __( 'of the month', AI1EC_PLUGIN_NAME );
1666
  }
1667
+ } elseif( $rc->get_property( 'byday' ) ) {
1668
  $_days = '';
1669
+ foreach( $rc->get_property( 'byday' ) as $d ) {
1670
  $_dnum = substr( $d, 0, 1);
1671
  $_day = substr( $d, 1, 3 );
1672
  $dnum = ' ' . date_i18n( "jS", strtotime( $_dnum . '-01-1998 12:00:00' ) );
1677
  }
1678
  break;
1679
  case 'yearly':
1680
+ if( $rc->get_property( 'bymonth' )) {
1681
  // if there are more than 2 months
1682
+ if( count( $rc->get_property( 'bymonth' )) > 2 ) {
1683
  $_months = '';
1684
+ foreach( $rc->get_property( 'bymonth' )as $_m ) {
1685
  $_m = $_m < 10 ? 0 . $_m : $_m;
1686
  $_months .= ' ' . $wp_locale->month_abbrev[$wp_locale->month[$_m]] . ',';
1687
  }
1688
  $_months = substr( $_months, 0, -1 );
1689
  $txt .= ' ' . _x( 'on', 'Recurrence editor - yearly tab', AI1EC_PLUGIN_NAME ) . $_months;
1690
+ } else if( count( $rc->get_property( 'bymonth' )) > 1 ) {
1691
  $_months = '';
1692
+ foreach( $rc->get_property( 'bymonth' )as $_m ) {
1693
  $_m = $_m < 10 ? 0 . $_m : $_m;
1694
  $_months .= ' ' . $wp_locale->month[$_m] . ' ' . __( 'and', AI1EC_PLUGIN_NAME );
1695
  }
1697
  $txt .= ' ' . _x( 'on', 'Recurrence editor - yearly tab', AI1EC_PLUGIN_NAME ) . $_months;
1698
  } else {
1699
  $_months = '';
1700
+ foreach( $rc->get_property( 'bymonth' )as $_m ) {
1701
  $_m = $_m < 10 ? 0 . $_m : $_m;
1702
  $_months .= ' ' . $wp_locale->month[$_m];
1703
  }
1798
  * @return void
1799
  **/
1800
  function _ending_sentence( &$txt, &$rc ) {
1801
+ if( $until = $rc->get_property( 'until' ) ) {
1802
  if( ! is_int( $until ) )
1803
  $until = strtotime( $until );
1804
  $txt .= ' ' . sprintf( __( 'until %s', AI1EC_PLUGIN_NAME ), date_i18n( get_option( 'date_format' ), $until, true ) );
1805
  }
1806
+ else if( $count = $rc->get_property( 'count' ) )
1807
  $txt .= ' ' . sprintf( __( 'for %d occurrences', AI1EC_PLUGIN_NAME ), $count );
1808
  else
1809
  $txt .= ' - ' . __( 'forever', AI1EC_PLUGIN_NAME );
1888
  $rule = empty( $event->exception_rules ) ? '' : $event->exception_rules;
1889
  }
1890
 
1891
+ $recurrence_helper = new Ai1ec_Recurrence_Helper( $rule );
1892
 
1893
+ if( $until = $recurrence_helper->get_property( 'until' ) ) {
1894
  $until = ( is_numeric( $until ) ) ? $until : strtotime( $until );
1895
  }
1896
+ else if( $count = $recurrence_helper->get_property( 'count' ) ) {
1897
  $count = ( is_numeric( $count ) ) ? $count : 100;
1898
  }
1899
  } catch( Ai1ec_Event_Not_Found $e ) { /* event wasn't found, keep defaults */ }
app/helper/class-ai1ec-importer-helper.php CHANGED
@@ -90,14 +90,7 @@ class Ai1ec_Importer_Helper {
90
  $count = 0;
91
 
92
  // include ical parser
93
- if( version_compare( PHP_VERSION, '5.3.0' ) >= 0 ) {
94
- // Parser that requires PHP v5.3.0 or up
95
- require_once( AI1EC_LIB_PATH . '/iCalcreator-2.14/iCalcreator.class.php' );
96
- } else {
97
- // Parser that works on PHP versions below 5.3.0
98
- require_once( AI1EC_LIB_PATH . '/iCalcreator-2.10/iCalcreator.class.php' );
99
- require_once( AI1EC_LIB_PATH . '/iCalcreator-2.10/iCalUtilityFunctions.class.php' );
100
- }
101
 
102
  // set unique id, required if any component UID is missing
103
  $config = array( 'unique_id' => 'ai1ec' );
90
  $count = 0;
91
 
92
  // include ical parser
93
+ require_once( AI1EC_LIB_PATH . '/iCalcreator-2.16/iCalcreator.class.php' );
 
 
 
 
 
 
 
94
 
95
  // set unique id, required if any component UID is missing
96
  $config = array( 'unique_id' => 'ai1ec' );
app/helper/class-ai1ec-recurrence-helper.php ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Handles parsing of ICS recurrence rules
5
+ *
6
+ * @author Time.ly Network, Inc.
7
+ * @since 1.10.3
8
+ */
9
+ class Ai1ec_Recurrence_Helper
10
+ {
11
+
12
+ /**
13
+ * @var string Parsed rule copy
14
+ */
15
+ public $rrule;
16
+
17
+ /**
18
+ * @var array Map of parsed rule keys and values
19
+ */
20
+ protected $_properties = array();
21
+
22
+ /**
23
+ * @var array Replacement keys to use in rules cleanup
24
+ */
25
+ protected $replacements = array(
26
+ 'from' => array( '\\,', '\\n', '\\;', '\\:', '\\"',),
27
+ 'to' => array( ',', "\n", ';', ':', '"', ),
28
+ );
29
+
30
+ /**
31
+ * @var array Map of properties possibly having comma-separated values
32
+ */
33
+ protected $comma_separated_properties = array(
34
+ 'bysecond' => true,
35
+ 'byminute' => true,
36
+ 'byhour' => true,
37
+ 'byday' => true,
38
+ 'bymonthday' => true,
39
+ 'byyearday' => true,
40
+ 'byyearno' => true,
41
+ 'bymonth' => true,
42
+ 'bysetpos' => true,
43
+ );
44
+
45
+ /**
46
+ * Constructor
47
+ *
48
+ * @param string $rrule Recurrence rule to initiate with
49
+ *
50
+ * @return void Constructor does not return
51
+ */
52
+ public function __construct( $rrule ) {
53
+ $this->parse_recurrence_rule( $rrule );
54
+ }
55
+
56
+ /**
57
+ * Parse arbitrary recurrence rule into keys and values
58
+ *
59
+ * @param string $rrule Recurrence rule to initiate with
60
+ *
61
+ * @return void Method doesn't return
62
+ */
63
+ public function parse_recurrence_rule( $rrule ) {
64
+ $this->_properties = array();
65
+ // some clean up
66
+ $rrule = trim( $rrule );
67
+ $rrule = str_replace(
68
+ $this->replacements['from'],
69
+ $this->replacements['to'],
70
+ $rrule
71
+ );
72
+
73
+ $this->rrule = $rrule;
74
+ $recurrence_rule_properties = explode( ';', $rrule );
75
+
76
+ foreach ( $recurrence_rule_properties as $property ) {
77
+ $property = trim( $property );
78
+ if ( empty( $property ) ) {
79
+ continue;
80
+ }
81
+ // it's always name=value
82
+ $exploded_property = explode( '=', $property );
83
+
84
+ $property_name = strtolower( $exploded_property[0] );
85
+ $property_value = $exploded_property[1];
86
+
87
+ //split up the list of values into an array (if it's a list)
88
+ if ( isset( $this->comma_separated_properties[$property_name] ) ) {
89
+ $property_value = explode( ',', $property_value );
90
+ }
91
+ $this->_properties[$property_name] = $property_value;
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Return the value for requested property
97
+ *
98
+ * @param string $property Name of property to get
99
+ * @param mixed $default Value to return when property doesn't exist [optional=false]
100
+ *
101
+ * @return mixed Value or $default
102
+ */
103
+ public function get_property( $property, $default = false ) {
104
+ if ( isset( $this->_properties[$property] ) ) {
105
+ return $this->_properties[$property];
106
+ }
107
+ return $default;
108
+ }
109
+
110
+ }
app/model/class-ai1ec-event.php CHANGED
@@ -870,17 +870,6 @@ class Ai1ec_Event {
870
  return $this->end;
871
  }
872
 
873
- /**
874
- * getFrequency function
875
- *
876
- * Returns the frequency of the event
877
- *
878
- * @return object
879
- **/
880
- function getFrequency( $excluded = array() ) {
881
- return new SG_iCal_Freq( $this->recurrence_rules, $this->start, $excluded );
882
- }
883
-
884
  /**
885
  * getDuration function
886
  *
870
  return $this->end;
871
  }
872
 
 
 
 
 
 
 
 
 
 
 
 
873
  /**
874
  * getDuration function
875
  *
app/model/class-ai1ec-settings.php CHANGED
@@ -262,6 +262,13 @@ class Ai1ec_Settings {
262
  */
263
  var $show_year_in_agenda_dates;
264
 
 
 
 
 
 
 
 
265
  /**
266
  * __construct function
267
  *
@@ -363,10 +370,11 @@ class Ai1ec_Settings {
363
  'geo_region_biasing' => FALSE,
364
  'show_data_notification' => TRUE,
365
  'show_intro_video' => TRUE,
366
- 'allow_statistics' => FALSE, // stats are opt-in
367
  'disable_autocompletion' => FALSE,
368
  'show_location_in_title' => TRUE,
369
  'show_year_in_agenda_dates' => FALSE,
 
370
  );
371
 
372
  foreach( $defaults as $key => $default ) {
@@ -462,6 +470,18 @@ class Ai1ec_Settings {
462
  update_option( 'ai1ec_settings', $this );
463
  }
464
 
 
 
 
 
 
 
 
 
 
 
 
 
465
  /**
466
  * Update setting of show_intro_video - whether to display the
467
  * intro video notice on the admin side.
262
  */
263
  var $show_year_in_agenda_dates;
264
 
265
+ /**
266
+ * Show the standard notification.
267
+ *
268
+ * @var bool
269
+ */
270
+ var $show_standard_notice;
271
+
272
  /**
273
  * __construct function
274
  *
370
  'geo_region_biasing' => FALSE,
371
  'show_data_notification' => TRUE,
372
  'show_intro_video' => TRUE,
373
+ 'allow_statistics' => FALSE, // stats are opt-in
374
  'disable_autocompletion' => FALSE,
375
  'show_location_in_title' => TRUE,
376
  'show_year_in_agenda_dates' => FALSE,
377
+ 'show_standard_notice' => TRUE,
378
  );
379
 
380
  foreach( $defaults as $key => $default ) {
470
  update_option( 'ai1ec_settings', $this );
471
  }
472
 
473
+ /**
474
+ * Update setting of show_data_notification - whether to display data
475
+ * collection notice on the admin side.
476
+ *
477
+ * @param boolean $value The new setting for show_data_notification.
478
+ * @return void
479
+ */
480
+ function update_standard_notification( $value = FALSE ) {
481
+ $this->show_standard_notice = $value;
482
+ update_option( 'ai1ec_settings', $this );
483
+ }
484
+
485
  /**
486
  * Update setting of show_intro_video - whether to display the
487
  * intro video notice on the admin side.
app/view/admin/box_support.php CHANGED
@@ -23,7 +23,7 @@
23
  <div class="ai1ec-download row-fluid">
24
  <div class="span6">
25
  <div>
26
- <a href="<?php echo admin_url( 'edit.php?post_type=' . AI1EC_POST_TYPE . '&amp;page=' . AI1EC_PLUGIN_NAME . '-upgrade' ) ?>" class="btn btn-large ai1ec-download-btn">
27
  <?php printf(
28
  __( 'Upgrade to the %s for free', AI1EC_PLUGIN_NAME ),
29
  '<div><i class="timely-icon-gift"></i> ' .
23
  <div class="ai1ec-download row-fluid">
24
  <div class="span6">
25
  <div>
26
+ <a href="http://support.time.ly/difference-lite-standard-versions/" class="btn btn-large ai1ec-download-btn">
27
  <?php printf(
28
  __( 'Upgrade to the %s for free', AI1EC_PLUGIN_NAME ),
29
  '<div><i class="timely-icon-gift"></i> ' .
app/view/admin/js/add_new_event.js CHANGED
@@ -348,7 +348,32 @@ jQuery( function( $ ){
348
  }
349
  });
350
  });
 
 
 
 
 
 
 
 
 
351
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  /**
353
  * Click event handler for Dismiss button of intro video.
354
  * That disables the intro video notification for admin users.
348
  }
349
  });
350
  });
351
+ /**
352
+ * Click event handler for Dismiss button
353
+ * that disables the data notification for admin users
354
+ */
355
+ $( '.ai1ec-dismiss-standard-notification' ).live( 'click', function() {
356
+ var $button = $( this );
357
+ var $parent = $( this ).parent().parent();
358
+ // disable the update button
359
+ $button.attr( 'disabled', true );
360
 
361
+ // create the data to send
362
+ var data = {
363
+ action: 'ai1ec_disable_standard_notice',
364
+ note: false
365
+ };
366
+
367
+ $.post( ajaxurl, data, function( response ) {
368
+ if( response.error ) {
369
+ // tell the user that there is an error
370
+ alert( response.message );
371
+ } else {
372
+ // hide notification message
373
+ $parent.remove();
374
+ }
375
+ });
376
+ });
377
  /**
378
  * Click event handler for Dismiss button of intro video.
379
  * That disables the intro video notification for admin users.
lib/SG_iCal.php DELETED
@@ -1,126 +0,0 @@
1
- <?php
2
-
3
- define('SG_ICALREADER_VERSION', '0.7.0');
4
-
5
- /**
6
- * A simple iCal parser. Should take care of most stuff for ya
7
- * http://github.com/fangel/SG-iCalendar
8
- *
9
- * Roadmap:
10
- * * Finish FREQUENCY-parsing.
11
- * * Add API for recurring events
12
- *
13
- * A simple example:
14
- * <?php
15
- * $ical = new SG_iCalReader("http://example.com/calendar.ics");
16
- * foreach( $ical->getEvents() As $event ) {
17
- * // Do stuff with the event $event
18
- * }
19
- * ?>
20
- *
21
- * @package SG_iCalReader
22
- * @author Morten Fangel (C) 2008
23
- * @author xonev (C) 2010
24
- * @author Tanguy Pruvot (C) 2010
25
- * @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
26
- */
27
- class SG_iCal {
28
-
29
- //objects
30
- public $information; //SG_iCal_VCalendar
31
- public $timezones; //SG_iCal_VTimeZone
32
-
33
- protected $events; //SG_iCal_VEvent[]
34
-
35
- /**
36
- * Constructs a new iCalReader. You can supply the url now, or later using setUrl
37
- * @param $url string
38
- */
39
- public function __construct($url = false) {
40
- $this->setUrl($url);
41
- }
42
-
43
- /**
44
- * Sets (or resets) the url this reader reads from.
45
- * @param $url string
46
- */
47
- public function setUrl( $url = false ) {
48
- if( $url !== false ) {
49
- SG_iCal_Parser::Parse($url, $this);
50
- }
51
- }
52
-
53
- /**
54
- * Returns the main calendar info. You can then query the returned
55
- * object with ie getTitle().
56
- * @return SG_iCal_VCalendar
57
- */
58
- public function getCalendarInfo() {
59
- return $this->information;
60
- }
61
-
62
- /**
63
- * Sets the calendar info for this calendar
64
- * @param SG_iCal_VCalendar $info
65
- */
66
- public function setCalendarInfo( SG_iCal_VCalendar $info ) {
67
- $this->information = $info;
68
- }
69
-
70
-
71
- /**
72
- * Returns a given timezone for the calendar. This is mainly used
73
- * by VEvents to adjust their date-times if they have specified a
74
- * timezone.
75
- *
76
- * If no timezone is given, all timezones in the calendar is
77
- * returned.
78
- *
79
- * @param $tzid string
80
- * @return SG_iCal_VTimeZone
81
- */
82
- public function getTimeZoneInfo( $tzid = null ) {
83
- if( $tzid == null ) {
84
- return $this->timezones;
85
- } else {
86
- if ( !isset($this->timezones)) {
87
- return null;
88
- }
89
- foreach( $this->timezones AS $tz ) {
90
- if( $tz->getTimeZoneId() == $tzid ) {
91
- return $tz;
92
- }
93
- }
94
- return null;
95
- }
96
- }
97
-
98
- /**
99
- * Adds a new timezone to this calendar
100
- * @param SG_iCal_VTimeZone $tz
101
- */
102
- public function addTimeZone( SG_iCal_VTimeZone $tz ) {
103
- $this->timezones[] = $tz;
104
- }
105
-
106
- /**
107
- * Returns the events found
108
- * @return array
109
- */
110
- public function getEvents() {
111
- return $this->events;
112
- }
113
-
114
- /**
115
- * Adds a event to this calendar
116
- * @param SG_iCal_VEvent $event
117
- */
118
- public function addEvent( SG_iCal_VEvent $event ) {
119
- $this->events[] = $event;
120
- }
121
- }
122
-
123
- /**
124
- * For legacy reasons, we keep the name SG_iCalReader..
125
- */
126
- class SG_iCalReader extends SG_iCal {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/blocks/SG_iCal_VCalendar.php DELETED
@@ -1,64 +0,0 @@
1
- <?php // BUILD: Remove line
2
-
3
- /**
4
- * The wrapper for the main vcalendar data. Used instead of ArrayObject
5
- * so you can easily query for title and description.
6
- * Exposes a iterator that will loop though all the data
7
- *
8
- * @package SG_iCalReader
9
- * @author Morten Fangel (C) 2008
10
- * @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
11
- */
12
- class SG_iCal_VCalendar implements IteratorAggregate {
13
- protected $data;
14
-
15
- /**
16
- * Creates a new SG_iCal_VCalendar.
17
- */
18
- public function __construct($data) {
19
- $this->data = $data;
20
- }
21
-
22
- /**
23
- * Returns the title of the calendar. If no title is known, NULL
24
- * will be returned
25
- * @return string
26
- */
27
- public function getTitle() {
28
- if( isset($this->data['x-wr-calname']) ) {
29
- return $this->data['x-wr-calname'];
30
- } else {
31
- return null;
32
- }
33
- }
34
-
35
- /**
36
- * Returns the description of the calendar. If no description is
37
- * known, NULL will be returned.
38
- * @return string
39
- */
40
- public function getDescription() {
41
- if( isset($this->data['x-wr-caldesc']) ) {
42
- return $this->data['x-wr-caldesc'];
43
- } else {
44
- return null;
45
- }
46
- }
47
-
48
- public function getTimezone() {
49
- if( isset($this->data['x-wr-timezone']) ) {
50
- return $this->data['x-wr-timezone'];
51
- } else {
52
- return null;
53
- }
54
- }
55
-
56
- /**
57
- * @see IteratorAggregate.getIterator()
58
- */
59
- public function getIterator() {
60
- return new ArrayIterator($this->data);
61
- }
62
- }
63
-
64
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/blocks/SG_iCal_VEvent.php DELETED
@@ -1,292 +0,0 @@
1
- <?php // BUILD: Remove line
2
-
3
- /**
4
- * The wrapper for vevents. Will reveal a unified and simple api for
5
- * the events, which include always finding a start and end (except
6
- * when no end or duration is given) and checking if the event is
7
- * blocking or similar.
8
- *
9
- * Will apply the specified timezone to timestamps if a tzid is
10
- * specified
11
- *
12
- * @package SG_iCalReader
13
- * @author Morten Fangel (C) 2008
14
- * @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
15
- */
16
- class SG_iCal_VEvent {
17
- const DEFAULT_CONFIRMED = true;
18
-
19
- public $uid;
20
-
21
- public $start;
22
- public $end;
23
-
24
- public $summary;
25
- public $description;
26
- public $location;
27
-
28
- public $laststart;
29
- public $lastend;
30
-
31
- public $recurrence; //RRULE
32
- public $recurex; //EXRULE
33
- public $excluded; //EXDATE(s)
34
- public $added; //RDATE(s)
35
-
36
- public $freq; //getFrequency() SG_iCal_Freq
37
-
38
- public $data;
39
-
40
- /**
41
- * Constructs a new SG_iCal_VEvent. Needs the SG_iCalReader
42
- * supplied so it can query for timezones.
43
- * @param SG_iCal_Line[] $data
44
- * @param SG_iCalReader $ical
45
- */
46
- public function __construct($data, SG_iCal $ical) {
47
-
48
- $this->uid = $data['uid']->getData();
49
- unset($data['uid']);
50
-
51
- if ( isset($data['rrule']) ) {
52
- $this->recurrence = new SG_iCal_Recurrence($data['rrule']);
53
- unset($data['rrule']);
54
- }
55
-
56
- if ( isset($data['exrule']) ) {
57
- $this->recurex = new SG_iCal_Recurrence($data['exrule']);
58
- unset($data['exrule']);
59
- }
60
-
61
- if( isset($data['dtstart']) ) {
62
- $this->start = $this->getTimestamp($data['dtstart'], $ical);
63
- unset($data['dtstart']);
64
- }
65
-
66
- if( isset($data['dtend']) ) {
67
- $this->end = $this->getTimestamp($data['dtend'], $ical);
68
- unset($data['dtend']);
69
- } elseif( isset($data['duration']) ) {
70
- $dur = new SG_iCal_Duration( $data['duration']->getData() );
71
- $this->end = $this->start + $dur->getDuration();
72
- unset($data['duration']);
73
- }
74
-
75
- //google cal set dtend as end of initial event (duration)
76
- if ( isset($this->recurrence) ) {
77
- //if there is a recurrence rule
78
-
79
- //exclusions
80
- if ( isset($data['exdate']) ) {
81
- foreach ($data['exdate'] as $exdate) {
82
- foreach ($exdate->getDataAsArray() as $ts) {
83
- $this->excluded[] = strtotime($ts);
84
- }
85
- }
86
- unset($data['exdate']);
87
- }
88
- //additions
89
- if ( isset($data['rdate']) ) {
90
- foreach ($data['rdate'] as $rdate) {
91
- foreach ($rdate->getDataAsArray() as $ts) {
92
- $this->added[] = strtotime($ts);
93
- }
94
- }
95
- unset($data['rdate']);
96
- }
97
-
98
- $until = $this->recurrence->getUntil();
99
- $count = $this->recurrence->getCount();
100
- //check if there is either 'until' or 'count' set
101
- if ( $until ) {
102
- //ok..
103
- } elseif ($count) {
104
- //if count is set, then figure out the last occurrence and set that as the end date
105
- $this->getFrequency();
106
- $until = $this->freq->lastOccurrence($this->start);
107
- } else {
108
- //forever... limit to 3 years
109
- $this->recurrence->setUntil('+3 years');
110
- $until = $this->recurrence->getUntil();
111
- }
112
- //date_default_timezone_set( xx ) needed ?;
113
- $this->laststart = strtotime($until);
114
- $this->lastend = $this->laststart + $this->getDuration();
115
- }
116
-
117
- $imports = array('summary','description','location');
118
- foreach( $imports AS $import ) {
119
- if( isset($data[$import]) ) {
120
- $this->$import = $data[$import]->getData();
121
- unset($data[$import]);
122
- }
123
- }
124
-
125
- if( isset($this->previous_tz) ) {
126
- date_default_timezone_set($this->previous_tz);
127
- }
128
-
129
- $this->data = SG_iCal_Line::Remove_Line($data);
130
- }
131
-
132
-
133
- /**
134
- * Returns the Event Occurrences Iterator (if recurrence set)
135
- * @return SG_iCal_Freq
136
- */
137
- public function getFrequency() {
138
- if (! isset($this->freq)) {
139
- if ( isset($this->recurrence) ) {
140
- $this->freq = new SG_iCal_Freq($this->recurrence->rrule, $this->start, $this->excluded, $this->added);
141
- }
142
- }
143
- return $this->freq;
144
- }
145
-
146
- /**
147
- * Returns the UID of the event
148
- * @return string
149
- */
150
- public function getUID() {
151
- return $this->uid;
152
- }
153
-
154
- /**
155
- * Returns the summary (or null if none is given) of the event
156
- * @return string
157
- */
158
- public function getSummary() {
159
- return $this->summary;
160
- }
161
-
162
- /**
163
- * Returns the description (or null if none is given) of the event
164
- * @return string
165
- */
166
- public function getDescription() {
167
- return $this->description;
168
- }
169
-
170
- /**
171
- * Returns the location (or null if none is given) of the event
172
- * @return string
173
- */
174
- public function getLocation() {
175
- return $this->location;
176
- }
177
-
178
- /**
179
- * Returns true if the event is blocking (ie not transparent)
180
- * @return bool
181
- */
182
- public function isBlocking() {
183
- return !(isset($this->data['transp']) && $this->data['transp'] == 'TRANSPARENT');
184
- }
185
-
186
- /**
187
- * Returns true if the event is confirmed
188
- * @return bool
189
- */
190
- public function isConfirmed() {
191
- if( !isset($this->data['status']) ) {
192
- return self::DEFAULT_CONFIRMED;
193
- } else {
194
- return $this->data['status'] == 'CONFIRMED';
195
- }
196
- }
197
-
198
- /**
199
- * Returns true if duration is multiple of 86400
200
- * @return bool
201
- */
202
- public function isWholeDay() {
203
- $dur = $this->getDuration();
204
- if ($dur > 0 && ($dur % 86400) == 0) {
205
- return true;
206
- }
207
- return false;
208
- }
209
-
210
- /**
211
- * Returns the timestamp for the beginning of the event
212
- * @return int
213
- */
214
- public function getStart() {
215
- return $this->start;
216
- }
217
-
218
- /**
219
- * Returns the timestamp for the end of the event
220
- * @return int
221
- */
222
- public function getEnd() {
223
- return $this->end;
224
- }
225
-
226
- /**
227
- * Returns the timestamp for the end of the last event
228
- * @return int
229
- */
230
- public function getRangeEnd() {
231
- return max($this->end,$this->lastend);
232
- }
233
-
234
- /**
235
- * Returns the duration of this event in seconds
236
- * @return int
237
- */
238
- public function getDuration() {
239
- return $this->end - $this->start;
240
- }
241
-
242
- /**
243
- * Returns the given property of the event.
244
- * @param string $prop
245
- * @return string
246
- */
247
- public function getProperty( $prop ) {
248
- if( isset($this->$prop) ) {
249
- return $this->$prop;
250
- } elseif( isset($this->data[$prop]) ) {
251
- return $this->data[$prop];
252
- } else {
253
- return null;
254
- }
255
- }
256
-
257
-
258
-
259
- /**
260
- * Set default timezone (temporary) to get timestamps
261
- * @return string
262
- */
263
- protected function setLineTimeZone(SG_iCal_Line $line) {
264
- if( isset($line['tzid']) ) {
265
- if (!isset($this->previous_tz)) {
266
- $this->previous_tz = @ date_default_timezone_get();
267
- }
268
- $this->tzid = $line['tzid'];
269
- date_default_timezone_set($this->tzid);
270
- return true;
271
- }
272
- return false;
273
- }
274
-
275
- /**
276
- * Calculates the timestamp from a DT line.
277
- * @param $line SG_iCal_Line
278
- * @return int
279
- */
280
- protected function getTimestamp( SG_iCal_Line $line, SG_iCal $ical ) {
281
-
282
- if( isset($line['tzid']) ) {
283
- $this->setLineTimeZone($line);
284
- //$tz = $ical->getTimeZoneInfo($line['tzid']);
285
- //$offset = $tz->getOffset($ts);
286
- //$ts = strtotime(date('D, d M Y H:i:s', $ts) . ' ' . $offset);
287
- }
288
- $ts = strtotime($line->getData());
289
-
290
- return $ts;
291
- }
292
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/blocks/SG_iCal_VTimeZone.php DELETED
@@ -1,95 +0,0 @@
1
- <?php // BUILD: Remove line
2
-
3
- /**
4
- * The wrapper for vtimezones. Stores the timezone-id and the setup for
5
- * daylight savings and standard time.
6
- *
7
- * @package SG_iCalReader
8
- * @author Morten Fangel (C) 2008
9
- * @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
10
- */
11
- class SG_iCal_VTimeZone {
12
- protected $tzid;
13
- protected $daylight;
14
- protected $standard;
15
- protected $cache = array();
16
-
17
- /**
18
- * Constructs a new SG_iCal_VTimeZone
19
- */
20
- public function __construct( $data ) {
21
- require_once dirname(__FILE__).'/../helpers/SG_iCal_Freq.php'; // BUILD: Remove line
22
-
23
- $this->tzid = $data['tzid'];
24
- $this->daylight = $data['daylight'];
25
- $this->standard = $data['standard'];
26
- }
27
-
28
- /**
29
- * Returns the timezone-id for this timezone. (Used to
30
- * differentiate between different tzs in a calendar)
31
- * @return string
32
- */
33
- public function getTimeZoneId() {
34
- return $this->tzid;
35
- }
36
-
37
- /**
38
- * Returns the given offset in this timezone for the given
39
- * timestamp. (eg +0200)
40
- * @param int $ts
41
- * @return string
42
- */
43
- public function getOffset( $ts ) {
44
- $act = $this->getActive($ts);
45
- return $this->{$act}['tzoffsetto'];
46
- }
47
-
48
- /**
49
- * Returns the timezone name for the given timestamp (eg CEST)
50
- * @param int $ts
51
- * @return string
52
- */
53
- public function getTimeZoneName($ts) {
54
- $act = $this->getActive($ts);
55
- return $this->{$act}['tzname'];
56
- }
57
-
58
- /**
59
- * Determines which of the daylight or standard is the active
60
- * setting.
61
- * The call is cached for a given timestamp, so a call to
62
- * getOffset and getTimeZoneName with the same ts won't calculate
63
- * the answer twice.
64
- * @param int $ts
65
- * @return string standard|daylight
66
- */
67
- private function getActive( $ts ) {
68
-
69
- if (class_exists('DateTimeZone')) {
70
-
71
- //PHP >= 5.2
72
- $tz = new DateTimeZone( $this->tzid );
73
- $date = new DateTime("@$ts", $tz);
74
- return ($date->format('I') == 1) ? 'daylight' : 'standard';
75
-
76
- } else {
77
-
78
- if( isset($this->cache[$ts]) ) {
79
- return $this->cache[$ts];
80
- }
81
-
82
- $daylight_freq = new SG_iCal_Freq($this->daylight['rrule'], strtotime($this->daylight['dtstart']));
83
- $standard_freq = new SG_iCal_Freq($this->standard['rrule'], strtotime($this->standard['dtstart']));
84
- $last_standard = $standard_freq->previousOccurrence($ts);
85
- $last_dst = $daylight_freq->previousOccurrence($ts);
86
- if( $last_dst > $last_standard ) {
87
- $this->cache[$ts] = 'daylight';
88
- } else {
89
- $this->cache[$ts] = 'standard';
90
- }
91
-
92
- return $this->cache[$ts];
93
- }
94
- }
95
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/class-ai1ec-updater.php DELETED
@@ -1,109 +0,0 @@
1
- <?php
2
- //
3
- // class-ai1ec-updater.php
4
- // all-in-one-event-calendar
5
- //
6
- // Created by The Seed Studio on 2012-05-09.
7
- //
8
- include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
9
-
10
- class Ai1ec_Updater extends WP_Upgrader {
11
- function upgrade_strings() {
12
- $this->strings['up_to_date'] = __('The plugin is at the latest version.');
13
- $this->strings['no_package'] = __('Update package not available.');
14
- $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>&#8230;');
15
- $this->strings['unpack_package'] = __('Unpacking the update&#8230;');
16
- $this->strings['deactivate_plugin'] = __('Deactivating the plugin&#8230;');
17
- $this->strings['remove_old'] = __('Removing the old version of the plugin&#8230;');
18
- $this->strings['remove_old_failed'] = __('Could not remove the old plugin.');
19
- $this->strings['process_failed'] = __('Plugin update failed.');
20
- $this->strings['process_success'] = __('Plugin updated successfully.');
21
- }
22
- function upgrade( $plugin ) {
23
-
24
- $this->init();
25
- $this->upgrade_strings();
26
-
27
- add_filter('upgrader_pre_install', array(&$this, 'deactivate_plugin_before_upgrade'), 10, 2);
28
- add_filter('upgrader_clear_destination', array(&$this, 'delete_old_plugin'), 10, 4);
29
-
30
- $this->run(
31
- array(
32
- 'package' => AI1EC_UPDATES_URL,
33
- 'destination' => WP_PLUGIN_DIR,
34
- 'clear_destination' => true,
35
- 'clear_working' => true,
36
- 'hook_extra' => array(
37
- 'plugin' => $plugin
38
- )
39
- )
40
- );
41
-
42
- // Cleanup our hooks, in case something else does a upgrade on this connection.
43
- remove_filter( 'upgrader_pre_install', array( &$this, 'deactivate_plugin_before_upgrade' ) );
44
- remove_filter( 'upgrader_clear_destination', array( &$this, 'delete_old_plugin') );
45
-
46
- if( ! $this->result || is_wp_error( $this->result ) )
47
- return $this->result;
48
-
49
- // Force refresh of plugin update information
50
- delete_site_transient( 'update_plugins' );
51
- wp_cache_delete( 'plugins', 'plugins' );
52
-
53
- // activate the plugin
54
- activate_plugin( $plugin );
55
- echo '<p>Plugin activated.</p>';
56
- echo '<a href="' . admin_url( 'index.php' ) . '">Continue Here</a>';
57
- }
58
-
59
- //Hooked to pre_install
60
- function deactivate_plugin_before_upgrade( $return, $plugin ) {
61
-
62
- if( is_wp_error( $return ) ) //Bypass.
63
- return $return;
64
-
65
- $plugin = isset( $plugin['plugin'] ) ? $plugin['plugin'] : '';
66
- if( empty( $plugin ) )
67
- return new WP_Error( 'bad_request', $this->strings['bad_request'] );
68
-
69
- if( is_plugin_active( $plugin ) ) {
70
- $this->skin->feedback( 'deactivate_plugin' );
71
- //Deactivate the plugin silently, Prevent deactivation hooks from running.
72
- deactivate_plugins( $plugin, true );
73
- }
74
- }
75
-
76
- //Hooked to upgrade_clear_destination
77
- function delete_old_plugin( $removed, $local_destination, $remote_destination, $plugin ) {
78
- global $wp_filesystem;
79
-
80
- if( is_wp_error( $removed ) )
81
- return $removed; //Pass errors through.
82
-
83
- $plugin = isset( $plugin['plugin'] ) ? $plugin['plugin'] : '';
84
- if( empty( $plugin ) )
85
- return new WP_Error( 'bad_request', $this->strings['bad_request'] );
86
-
87
- $plugins_dir = $wp_filesystem->wp_plugins_dir();
88
- $this_plugin_dir = trailingslashit( dirname( $plugins_dir . $plugin ) );
89
-
90
- $ai1ec_themes = $wp_filesystem->wp_content_dir() . AI1EC_THEMES_FOLDER;
91
- if( $wp_filesystem->exists( $ai1ec_themes ) ) {
92
- $wp_filesystem->delete( $ai1ec_themes, true );
93
- }
94
-
95
- if( ! $wp_filesystem->exists( $this_plugin_dir ) ) //If its already vanished.
96
- return $removed;
97
-
98
- // If plugin is in its own directory, recursively delete the directory.
99
- if( strpos( $plugin, '/') && $this_plugin_dir != $plugins_dir ) //base check on if plugin includes directory separator AND that its not the root plugin folder
100
- $deleted = $wp_filesystem->delete( $this_plugin_dir, true );
101
- else
102
- $deleted = $wp_filesystem->delete( $plugins_dir . $plugin );
103
-
104
- if( ! $deleted )
105
- return new WP_Error( 'remove_old_failed', $this->strings['remove_old_failed'] );
106
-
107
- return true;
108
- }
109
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/global-functions.php CHANGED
@@ -26,38 +26,7 @@ function ai1ec_make_ints_array( $input, $separator = ',' ) {
26
  return $output;
27
  }
28
 
29
- /**
30
- * url_get_contents function
31
- *
32
- * @param string $url URL
33
- *
34
- * @return string
35
- **/
36
- function url_get_contents( $url ) {
37
- // holds the output
38
- $output = "";
39
-
40
- // To make a remote call in wordpress it's better to use the wrapper functions instead
41
- // of class methods. http://codex.wordpress.org/HTTP_API
42
- // SSL Verification was disabled in the cUrl call
43
- $result = wp_remote_get( $url, array( 'sslverify' => false, 'timeout' => 120 ) );
44
- // The wrapper functions return an WP_error if anything goes wrong.
45
- if( is_wp_error( $result ) ) {
46
- // We explicitly return false to notify an error. This is exactly the same behaviour we had before
47
- // because both curl_exec() and file_get_contents() returned false on error
48
- return FALSE;
49
- }
50
 
51
- $output = $result['body'];
52
-
53
- // check if data is utf-8
54
- if( ! SG_iCal_Parser::_ValidUtf8( $output ) ) {
55
- // Encode the data in utf-8
56
- $output = utf8_encode( $output );
57
- }
58
-
59
- return $output;
60
- }
61
 
62
  /**
63
  * is_curl_available function
26
  return $output;
27
  }
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  /**
32
  * is_curl_available function
lib/helpers/SG_iCal_Duration.php DELETED
@@ -1,56 +0,0 @@
1
- <?php // BUILD: Remove line
2
-
3
- /**
4
- * A class for calculating how many seconds a duration-string is
5
- *
6
- * @package SG_iCalReader
7
- * @author Morten Fangel (C) 2008
8
- * @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
9
- */
10
-
11
- class SG_iCal_Duration {
12
- protected $dur;
13
-
14
- /**
15
- * Constructs a new SG_iCal_Duration from a duration-rule.
16
- * The basic build-up of DURATIONs are:
17
- * (["+"] / "-") "P" (dur-date / dur-date + "T" + dur-time / dur-time / dur-week)
18
- * Is solved via a really fugly reg-exp with way to many ()'s..
19
- *
20
- * @param $duration string
21
- */
22
- public function __construct( $duration ) {
23
-
24
- $ts = 0;
25
-
26
- if (preg_match('/[\\+\\-]{0,1}P((\d+)W)?((\d+)D)?(T)?((\d+)H)?((\d+)M)?((\d+)S)?/', $duration, $matches) === 1) {
27
- $results = array(
28
- 'weeks'=> (int)@ $matches[2],
29
- 'days'=> (int)@ $matches[4],
30
- 'hours'=> (int)@ $matches[7],
31
- 'minutes'=>(int)@ $matches[9],
32
- 'seconds'=>(int)@ $matches[11]
33
- );
34
-
35
- $ts += $results['seconds'];
36
- $ts += 60 * $results['minutes'];
37
- $ts += 60 * 60 * $results['hours'];
38
- $ts += 24 * 60 * 60 * $results['days'];
39
- $ts += 7 * 24 * 60 * 60 * $results['weeks'];
40
- } else {
41
- // Invalid duration!
42
- }
43
-
44
- $dir = ($duration{0} == '-') ? -1 : 1;
45
-
46
- $this->dur = $dir * $ts;
47
- }
48
-
49
- /**
50
- * Returns the duration in seconds
51
- * @return int
52
- */
53
- public function getDuration() {
54
- return $this->dur;
55
- }
56
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/helpers/SG_iCal_Factory.php DELETED
@@ -1,42 +0,0 @@
1
- <?php // BUILD: Remove line
2
-
3
- /**
4
- * A simple Factory for converting a section/data pair into the
5
- * corrosponding block-object. If the section isn't known a simple
6
- * ArrayObject is used instead.
7
- *
8
- * @package SG_iCalReader
9
- * @author Morten Fangel (C) 2008
10
- * @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
11
- */
12
- class SG_iCal_Factory {
13
- /**
14
- * Returns a new block-object for the section/data-pair. The list
15
- * of returned objects is:
16
- *
17
- * vcalendar => SG_iCal_VCalendar
18
- * vtimezone => SG_iCal_VTimeZone
19
- * vevent => SG_iCal_VEvent
20
- * * => ArrayObject
21
- *
22
- * @param $ical SG_iCalReader The reader this section/data-pair belongs to
23
- * @param $section string
24
- * @param SG_iCal_Line[]
25
- */
26
- public static function factory( SG_iCal $ical, $section, $data ) {
27
- switch( $section ) {
28
- case "vcalendar":
29
- require_once dirname(__FILE__).'/../blocks/SG_iCal_VCalendar.php'; // BUILD: Remove line
30
- return new SG_iCal_VCalendar(SG_iCal_Line::Remove_Line($data), $ical );
31
- case "vtimezone":
32
- require_once dirname(__FILE__).'/../blocks/SG_iCal_VTimeZone.php'; // BUILD: Remove line
33
- return new SG_iCal_VTimeZone(SG_iCal_Line::Remove_Line($data), $ical );
34
- case "vevent":
35
- require_once dirname(__FILE__).'/../blocks/SG_iCal_VEvent.php'; // BUILD: Remove line
36
- return new SG_iCal_VEvent($data, $ical );
37
-
38
- default:
39
- return new ArrayObject(SG_iCal_Line::Remove_Line((array) $data) );
40
- }
41
- }
42
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/helpers/SG_iCal_Freq.php DELETED
@@ -1,559 +0,0 @@
1
- <?php // BUILD: Remove line
2
-
3
- /**
4
- * A class to store Frequency-rules in. Will allow a easy way to find the
5
- * last and next occurrence of the rule.
6
- *
7
- * No - this is so not pretty. But.. ehh.. You do it better, and I will
8
- * gladly accept patches.
9
- *
10
- * Created by trail-and-error on the examples given in the RFC.
11
- *
12
- * TODO: Update to a better way of doing calculating the different options.
13
- * Instead of only keeping track of the best of the current dates found
14
- * it should instead keep a array of all the calculated dates within the
15
- * period.
16
- * This should fix the issues with multi-rule + multi-rule interference,
17
- * and make it possible to implement the SETPOS rule.
18
- * By pushing the next period onto the stack as the last option will
19
- * (hopefully) remove the need for the awful simpleMode
20
- *
21
- * @package SG_iCalReader
22
- * @author Morten Fangel (C) 2008
23
- * @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
24
- */
25
- class SG_iCal_Freq {
26
- protected $weekdays = array('MO'=>'monday', 'TU'=>'tuesday', 'WE'=>'wednesday', 'TH'=>'thursday', 'FR'=>'friday', 'SA'=>'saturday', 'SU'=>'sunday');
27
- protected $knownRules = array('month', 'weekno', 'day', 'monthday', 'yearday', 'hour', 'minute'); //others : 'setpos', 'second'
28
- protected $ruleModifiers = array('wkst');
29
- protected $simpleMode = true;
30
-
31
- protected $rules = array('freq'=>'yearly', 'interval'=>1);
32
- protected $start = 0;
33
- protected $freq = '';
34
-
35
- protected $excluded; //EXDATE
36
- protected $added; //RDATE
37
-
38
- protected $cache; // getAllOccurrences()
39
-
40
- /**
41
- * Constructs a new Freqency-rule
42
- * @param $rule string
43
- * @param $start int Unix-timestamp (important : Need to be the start of Event)
44
- * @param $excluded array of int (timestamps), see EXDATE documentation
45
- * @param $added array of int (timestamps), see RDATE documentation
46
- */
47
- public function __construct( $rule, $start, $excluded=array(), $added=array(), $exrule = false) {
48
- $this->start = $start;
49
- $this->excluded = array();
50
-
51
- $rules = array();
52
- foreach( explode(';', $rule) AS $v) {
53
- if( strpos( $v, '=' ) === false )
54
- continue;
55
-
56
- list($k, $v) = explode('=', $v);
57
- $this->rules[ strtolower($k) ] = $v;
58
- }
59
-
60
- if( isset($this->rules['until']) && is_string($this->rules['until']) ) {
61
- $this->rules['until'] = strtotime($this->rules['until']);
62
- }
63
- $this->freq = strtolower($this->rules['freq']);
64
-
65
- foreach( $this->knownRules AS $rule ) {
66
- if( isset($this->rules['by' . $rule]) ) {
67
- if( $this->isPrerule($rule, $this->freq) ) {
68
- $this->simpleMode = false;
69
- }
70
- }
71
- }
72
-
73
- if(!$this->simpleMode) {
74
- if(! (isset($this->rules['byday']) || isset($this->rules['bymonthday']) || isset($this->rules['byyearday']))) {
75
- $this->rules['bymonthday'] = date('d', $this->start);
76
- }
77
- }
78
-
79
- //set until, and cache
80
- if( isset($this->rules['count']) ) {
81
- if( $exrule )
82
- $this->rules['count']++;
83
-
84
- $cache[$ts] = $ts = $this->start;
85
- for($n=1; $n < $this->rules['count']; $n++) {
86
- $ts = $this->findNext($ts);
87
- $cache[$ts] = $ts;
88
- }
89
- $this->rules['until'] = $ts;
90
-
91
- //EXDATE
92
- if (!empty($excluded)) {
93
- foreach($excluded as $ts) {
94
- unset($cache[$ts]);
95
- }
96
- }
97
- //RDATE
98
- if (!empty($added)) {
99
- $cache = $cache + $added;
100
- asort($cache);
101
- }
102
-
103
- $this->cache = array_values($cache);
104
- }
105
-
106
- $this->excluded = $excluded;
107
- $this->added = $added;
108
- }
109
-
110
-
111
- /**
112
- * Returns all timestamps array(), build the cache if not made before
113
- * @return array
114
- */
115
- public function getAllOccurrences() {
116
- if (empty($this->cache)) {
117
- //build cache
118
- $next = $this->firstOccurrence();
119
- while ($next) {
120
- $cache[] = $next;
121
- $next = $this->findNext($next);
122
- }
123
- if (!empty($this->added)) {
124
- $cache = $cache + $this->added;
125
- asort($cache);
126
- }
127
- $this->cache = $cache;
128
- }
129
- return $this->cache;
130
- }
131
-
132
- /**
133
- * Returns the previous (most recent) occurrence of the rule from the
134
- * given offset
135
- * @param int $offset
136
- * @return int
137
- */
138
- public function previousOccurrence( $offset ) {
139
- if (!empty($this->cache)) {
140
- $t2=$this->start;
141
- foreach($this->cache as $ts) {
142
- if ($ts >= $offset)
143
- return $t2;
144
- $t2 = $ts;
145
- }
146
- } else {
147
- $ts = $this->start;
148
- while( ($t2 = $this->findNext($ts)) < $offset) {
149
- if( $t2 == false ){
150
- break;
151
- }
152
- $ts = $t2;
153
- }
154
- }
155
- return $ts;
156
- }
157
-
158
- /**
159
- * Returns the next occurrence of this rule after the given offset
160
- * @param int $offset
161
- * @return int
162
- */
163
- public function nextOccurrence( $offset ) {
164
- if ($offset < $this->start)
165
- return $this->firstOccurrence();
166
- return $this->findNext($offset);
167
- }
168
-
169
- /**
170
- * Finds the first occurrence of the rule.
171
- * @return int timestamp
172
- */
173
- public function firstOccurrence() {
174
- $t = $this->start;
175
- if ( is_array( $this->excluded ) && in_array($t, $this->excluded))
176
- $t = $this->findNext($t);
177
- return $t;
178
- }
179
-
180
- /**
181
- * Finds the absolute last occurrence of the rule from the given offset.
182
- * Builds also the cache, if not set before...
183
- * @return int timestamp
184
- */
185
- public function lastOccurrence() {
186
- //build cache if not done
187
- $this->getAllOccurrences();
188
- //return last timestamp in cache
189
- return end($this->cache);
190
- }
191
-
192
- /**
193
- * Calculates the next time after the given offset that the rule
194
- * will apply.
195
- *
196
- * The approach to finding the next is as follows:
197
- * First we establish a timeframe to find timestamps in. This is
198
- * between $offset and the end of the period that $offset is in.
199
- *
200
- * We then loop though all the rules (that is a Prerule in the
201
- * current freq.), and finds the smallest timestamp inside the
202
- * timeframe.
203
- *
204
- * If we find something, we check if the date is a valid recurrence
205
- * (with validDate). If it is, we return it. Otherwise we try to
206
- * find a new date inside the same timeframe (but using the new-
207
- * found date as offset)
208
- *
209
- * If no new timestamps were found in the period, we try in the
210
- * next period
211
- *
212
- * @param int $offset
213
- * @return int
214
- */
215
- public function findNext($offset) {
216
- if (!empty($this->cache)) {
217
- foreach($this->cache as $ts) {
218
- if ($ts > $offset)
219
- return $ts;
220
- }
221
- }
222
-
223
- $debug = false;
224
-
225
- //make sure the offset is valid
226
- if( $offset === false || (isset($this->rules['until']) && $offset > $this->rules['until']) ) {
227
- if($debug) echo 'STOP: ' . date('r', $offset) . "\n";
228
- return false;
229
- }
230
-
231
- $found = true;
232
-
233
- //set the timestamp of the offset (ignoring hours and minutes unless we want them to be
234
- //part of the calculations.
235
- if($debug) echo 'O: ' . date('r', $offset) . "\n";
236
- $hour = (in_array($this->freq, array('hourly','minutely')) && $offset > $this->start) ? date('H', $offset) : date('H', $this->start);
237
- $minute = (($this->freq == 'minutely' || isset($this->rules['byminute'])) && $offset > $this->start) ? date('i', $offset) : date('i', $this->start);
238
- $t = mktime($hour, $minute, date('s', $this->start), date('m', $offset), date('d', $offset), date('Y',$offset));
239
- if($debug) echo 'START: ' . date('r', $t) . "\n";
240
-
241
- if( $this->simpleMode ) {
242
- if( $offset < $t ) {
243
- $ts = $t;
244
- if ($ts && in_array($ts, $this->excluded))
245
- $ts = $this->findNext($ts);
246
- } else {
247
- $ts = $this->findStartingPoint( $t, $this->rules['interval'], false );
248
- if( !$this->validDate( $ts ) ) {
249
- $ts = $this->findNext($ts);
250
- }
251
- }
252
- return $ts;
253
- }
254
-
255
- $eop = $this->findEndOfPeriod($offset);
256
- if($debug) echo 'EOP: ' . date('r', $eop) . "\n";
257
-
258
- foreach( $this->knownRules AS $rule ) {
259
- if( $found && isset($this->rules['by' . $rule]) ) {
260
- if( $this->isPrerule($rule, $this->freq) ) {
261
- $subrules = explode(',', $this->rules['by' . $rule]);
262
- $_t = null;
263
- foreach( $subrules AS $subrule ) {
264
- $imm = call_user_func_array(array($this, 'ruleBy' . $rule), array($subrule, $t));
265
- if( $imm === false ) {
266
- break;
267
- }
268
- if($debug) echo strtoupper($rule) . ': ' . date('r', $imm) . ' A: ' . ((int) ($imm > $offset && $imm < $eop)) . "\n";
269
- if( $imm > $offset && $imm < $eop && ($_t == null || $imm < $_t) ) {
270
- $_t = $imm;
271
- }
272
- }
273
- if( $_t !== null ) {
274
- $t = $_t;
275
- } else {
276
- $found = $this->validDate($t);
277
- }
278
- }
279
- }
280
- }
281
-
282
- if( $offset < $this->start && $this->start < $t ) {
283
- $ts = $this->start;
284
- } else if( $found && ($t != $offset)) {
285
- if( $this->validDate( $t ) ) {
286
- if($debug) echo 'OK' . "\n";
287
- $ts = $t;
288
- } else {
289
- if($debug) echo 'Invalid' . "\n";
290
- $ts = $this->findNext($t);
291
- }
292
- } else {
293
- if($debug) echo 'Not found' . "\n";
294
- $ts = $this->findNext( $this->findStartingPoint( $offset, $this->rules['interval'] ) );
295
- }
296
- if ( is_array( $this->excluded ) && $ts && in_array($ts, $this->excluded))
297
- return $this->findNext($ts);
298
-
299
- return $ts;
300
- }
301
-
302
- /**
303
- * Finds the starting point for the next rule. It goes $interval
304
- * 'freq' forward in time since the given offset
305
- * @param int $offset
306
- * @param int $interval
307
- * @param boolean $truncate
308
- * @return int
309
- */
310
- private function findStartingPoint( $offset, $interval, $truncate = true ) {
311
- $_freq = ($this->freq == 'daily') ? 'day__' : $this->freq;
312
- $t = '+' . $interval . ' ' . substr($_freq,0,-2) . 's';
313
- if( $_freq == 'monthly' && $truncate ) {
314
- if( $interval > 1) {
315
- $offset = strtotime('+' . ($interval - 1) . ' months ', $offset);
316
- }
317
- $t = '+' . (date('t', $offset) - date('d', $offset) + 1) . ' days';
318
- }
319
-
320
- $sp = strtotime($t, $offset);
321
-
322
- if( $truncate ) {
323
- $sp = $this->truncateToPeriod($sp, $this->freq);
324
- }
325
-
326
- return $sp;
327
- }
328
-
329
- /**
330
- * Finds the earliest timestamp posible outside this perioid
331
- * @param int $offset
332
- * @return int
333
- */
334
- public function findEndOfPeriod($offset) {
335
- return $this->findStartingPoint($offset, 1);
336
- }
337
-
338
- /**
339
- * Resets the timestamp to the beginning of the
340
- * period specified by freq
341
- *
342
- * Yes - the fall-through is on purpose!
343
- *
344
- * @param int $time
345
- * @param int $freq
346
- * @return int
347
- */
348
- private function truncateToPeriod( $time, $freq ) {
349
- $date = getdate($time);
350
- switch( $freq ) {
351
- case "yearly":
352
- $date['mon'] = 1;
353
- case "monthly":
354
- $date['mday'] = 1;
355
- case "daily":
356
- $date['hours'] = 0;
357
- case 'hourly':
358
- $date['minutes'] = 0;
359
- case "minutely":
360
- $date['seconds'] = 0;
361
- break;
362
- case "weekly":
363
- if( date('N', $time) == 1) {
364
- $date['hours'] = 0;
365
- $date['minutes'] = 0;
366
- $date['seconds'] = 0;
367
- } else {
368
- $date = getdate(strtotime("last monday 0:00", $time));
369
- }
370
- break;
371
- }
372
- $d = mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']);
373
- return $d;
374
- }
375
-
376
- /**
377
- * Applies the BYDAY rule to the given timestamp
378
- * @param string $rule
379
- * @param int $t
380
- * @return int
381
- */
382
- private function ruleByday($rule, $t) {
383
- $dir = ($rule{0} == '-') ? -1 : 1;
384
- $dir_t = ($dir == 1) ? 'next' : 'last';
385
-
386
-
387
- $d = $this->weekdays[substr($rule,-2)];
388
- $s = $dir_t . ' ' . $d . ' ' . date('H:i:s',$t);
389
-
390
- if( $rule == substr($rule, -2) ) {
391
- if( date('l', $t) == ucfirst($d) ) {
392
- $s = 'today ' . date('H:i:s',$t);
393
- }
394
-
395
- $_t = strtotime($s, $t);
396
-
397
- if( $_t == $t && in_array($this->freq, array('monthly', 'yearly')) ) {
398
- // Yes. This is not a great idea.. but hey, it works.. for now
399
- $s = 'next ' . $d . ' ' . date('H:i:s',$t);
400
- $_t = strtotime($s, $_t);
401
- }
402
-
403
- return $_t;
404
- } else {
405
- $_f = $this->freq;
406
- if( isset($this->rules['bymonth']) && $this->freq == 'yearly' ) {
407
- $this->freq = 'monthly';
408
- }
409
- if( $dir == -1 ) {
410
- $_t = $this->findEndOfPeriod($t);
411
- } else {
412
- $_t = $this->truncateToPeriod($t, $this->freq);
413
- }
414
- $this->freq = $_f;
415
-
416
- $c = preg_replace('/[^0-9]/','',$rule);
417
- $c = ($c == '') ? 1 : $c;
418
-
419
- $n = $_t;
420
- while($c > 0 ) {
421
- if( $dir == 1 && $c == 1 && date('l', $t) == ucfirst($d) ) {
422
- $s = 'today ' . date('H:i:s',$t);
423
- }
424
- $n = strtotime($s, $n);
425
- $c--;
426
- }
427
-
428
- return $n;
429
- }
430
- }
431
-
432
- private function ruleBymonth($rule, $t) {
433
- $_t = mktime(date('H',$t), date('i',$t), date('s',$t), $rule, date('d', $t), date('Y', $t));
434
- if( $t == $_t && isset($this->rules['byday']) ) {
435
- // TODO: this should check if one of the by*day's exists, and have a multi-day value
436
- return false;
437
- } else {
438
- return $_t;
439
- }
440
- }
441
-
442
- private function ruleBymonthday($rule, $t) {
443
- if( $rule < 0 ) {
444
- $rule = date('t', $t) + $rule + 1;
445
- }
446
- return mktime(date('H',$t), date('i',$t), date('s',$t), date('m', $t), $rule, date('Y', $t));
447
- }
448
-
449
- private function ruleByyearday($rule, $t) {
450
- if( $rule < 0 ) {
451
- $_t = $this->findEndOfPeriod();
452
- $d = '-';
453
- } else {
454
- $_t = $this->truncateToPeriod($t, $this->freq);
455
- $d = '+';
456
- }
457
- $s = $d . abs($rule -1) . ' days ' . date('H:i:s',$t);
458
- return strtotime($s, $_t);
459
- }
460
-
461
- private function ruleByweekno($rule, $t) {
462
- if( $rule < 0 ) {
463
- $_t = $this->findEndOfPeriod();
464
- $d = '-';
465
- } else {
466
- $_t = $this->truncateToPeriod($t, $this->freq);
467
- $d = '+';
468
- }
469
-
470
- $sub = (date('W', $_t) == 1) ? 2 : 1;
471
- $s = $d . abs($rule - $sub) . ' weeks ' . date('H:i:s',$t);
472
- $_t = strtotime($s, $_t);
473
-
474
- return $_t;
475
- }
476
-
477
- private function ruleByhour($rule, $t) {
478
- $_t = mktime($rule, date('i',$t), date('s',$t), date('m',$t), date('d', $t), date('Y', $t));
479
- return $_t;
480
- }
481
-
482
- private function ruleByminute($rule, $t) {
483
- $_t = mktime(date('h',$t), $rule, date('s',$t), date('m',$t), date('d', $t), date('Y', $t));
484
- return $_t;
485
- }
486
-
487
- private function validDate( $t ) {
488
- if( isset($this->rules['until']) && $t > $this->rules['until'] ) {
489
- return false;
490
- }
491
-
492
- if ( is_array( $this->excluded ) && in_array($t, $this->excluded)) {
493
- return false;
494
- }
495
-
496
- if( isset($this->rules['bymonth']) ) {
497
- $months = explode(',', $this->rules['bymonth']);
498
- if( !in_array(date('m', $t), $months)) {
499
- return false;
500
- }
501
- }
502
- if( isset($this->rules['byday']) ) {
503
- $days = explode(',', $this->rules['byday']);
504
- foreach( $days As $i => $k ) {
505
- $days[$i] = $this->weekdays[ preg_replace('/[^A-Z]/', '', $k)];
506
- }
507
- if( !in_array(strtolower(date('l', $t)), $days)) {
508
- return false;
509
- }
510
- }
511
- if( isset($this->rules['byweekno']) ) {
512
- $weeks = explode(',', $this->rules['byweekno']);
513
- if( !in_array(date('W', $t), $weeks)) {
514
- return false;
515
- }
516
- }
517
- if( isset($this->rules['bymonthday'])) {
518
- $weekdays = explode(',', $this->rules['bymonthday']);
519
- foreach( $weekdays As $i => $k ) {
520
- if( $k < 0 ) {
521
- $weekdays[$i] = date('t', $t) + $k + 1;
522
- }
523
- }
524
- if( !in_array(date('d', $t), $weekdays)) {
525
- return false;
526
- }
527
- }
528
- if( isset($this->rules['byhour']) ) {
529
- $hours = explode(',', $this->rules['byhour']);
530
- if( !in_array(date('H', $t), $hours)) {
531
- return false;
532
- }
533
- }
534
-
535
- return true;
536
- }
537
-
538
- private function isPrerule($rule, $freq) {
539
- if( $rule == 'year')
540
- return false;
541
- if( $rule == 'month' && $freq == 'yearly')
542
- return true;
543
- if( $rule == 'monthday' && in_array($freq, array('yearly', 'monthly')) && !isset($this->rules['byday']))
544
- return true;
545
- // TODO: is it faster to do monthday first, and ignore day if monthday exists? - prolly by a factor of 4..
546
- if( $rule == 'yearday' && $freq == 'yearly' )
547
- return true;
548
- if( $rule == 'weekno' && $freq == 'yearly' )
549
- return true;
550
- if( $rule == 'day' && in_array($freq, array('yearly', 'monthly', 'weekly')))
551
- return true;
552
- if( $rule == 'hour' && in_array($freq, array('yearly', 'monthly', 'weekly', 'daily')))
553
- return true;
554
- if( $rule == 'minute' )
555
- return true;
556
-
557
- return false;
558
- }
559
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/helpers/SG_iCal_Line.php DELETED
@@ -1,165 +0,0 @@
1
- <?php // BUILD: Remove line
2
-
3
- /**
4
- * A class for storing a single (complete) line of the iCal file.
5
- * Will find the line-type, the arguments and the data of the file and
6
- * store them.
7
- *
8
- * The line-type can be found by querying getIdent(), data via either
9
- * getData() or typecasting to a string.
10
- * Params can be access via the ArrayAccess. A iterator is also avilable
11
- * to iterator over the params.
12
- *
13
- * @package SG_iCalReader
14
- * @author Morten Fangel (C) 2008
15
- * @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
16
- */
17
- class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
18
- protected $ident;
19
- protected $data;
20
- protected $params = array();
21
-
22
- protected $replacements = array('from'=>array('\\,', '\\n', '\\;', '\\:', '\\"'), 'to'=>array(',', "\n", ';', ':', '"'));
23
-
24
- /**
25
- * Constructs a new line.
26
- */
27
- public function __construct( $line ) {
28
- $split = strpos($line, ':');
29
- $idents = explode(';', substr($line, 0, $split));
30
- $ident = strtolower(array_shift($idents));
31
-
32
- $data = trim(substr($line, $split+1));
33
- $data = str_replace($this->replacements['from'], $this->replacements['to'], $data);
34
-
35
- $params = array();
36
- foreach( $idents AS $v) {
37
- list($k, $v) = explode('=', $v);
38
- $params[ strtolower($k) ] = $v;
39
- }
40
-
41
- $this->ident = $ident;
42
- $this->params = $params;
43
- $this->data = $data;
44
- }
45
-
46
- /**
47
- * Is this line the begining of a new block?
48
- * @return bool
49
- */
50
- public function isBegin() {
51
- return $this->ident == 'begin';
52
- }
53
-
54
- /**
55
- * Is this line the end of a block?
56
- * @return bool
57
- */
58
- public function isEnd() {
59
- return $this->ident == 'end';
60
- }
61
-
62
- /**
63
- * Returns the line-type (ident) of the line
64
- * @return string
65
- */
66
- public function getIdent() {
67
- return $this->ident;
68
- }
69
-
70
- /**
71
- * Returns the content of the line
72
- * @return string
73
- */
74
- public function getData() {
75
- return $this->data;
76
- }
77
-
78
- /**
79
- * Returns the content of the line
80
- * @return string
81
- */
82
- public function getDataAsArray() {
83
- if (strpos($this->data,",") !== false) {
84
- return explode(",",$this->data);
85
- }
86
- else
87
- return array($this->data);
88
- }
89
-
90
- /**
91
- * A static helper to get a array of SG_iCal_Line's, and calls
92
- * getData() on each of them to lay the data "bare"..
93
- *
94
- * @param SG_iCal_Line[]
95
- * @return array
96
- */
97
- public static function Remove_Line($arr) {
98
- $rtn = array();
99
- foreach( $arr AS $k => $v ) {
100
- if(is_array($v)) {
101
- $rtn[$k] = self::Remove_Line($v);
102
- } elseif( $v instanceof SG_iCal_Line ) {
103
- $rtn[$k] = $v->getData();
104
- } else {
105
- $rtn[$k] = $v;
106
- }
107
- }
108
- return $rtn;
109
- }
110
-
111
- /**
112
- * @see ArrayAccess.offsetExists
113
- */
114
- public function offsetExists( $param ) {
115
- return isset($this->params[ strtolower($param) ]);
116
- }
117
-
118
- /**
119
- * @see ArrayAccess.offsetGet
120
- */
121
- public function offsetGet( $param ) {
122
- $index = strtolower($param);
123
- if (isset($this->params[ $index ])) {
124
- return $this->params[ $index ];
125
- }
126
- }
127
-
128
- /**
129
- * Disabled ArrayAccess requirement
130
- * @see ArrayAccess.offsetSet
131
- */
132
- public function offsetSet( $param, $val ) {
133
- return false;
134
- }
135
-
136
- /**
137
- * Disabled ArrayAccess requirement
138
- * @see ArrayAccess.offsetUnset
139
- */
140
- public function offsetUnset( $param ) {
141
- return false;
142
- }
143
-
144
- /**
145
- * toString method.
146
- * @see getData()
147
- */
148
- public function __toString() {
149
- return $this->getData();
150
- }
151
-
152
- /**
153
- * @see Countable.count
154
- */
155
- public function count() {
156
- return count($this->params);
157
- }
158
-
159
- /**
160
- * @see IteratorAggregate.getIterator
161
- */
162
- public function getIterator() {
163
- return new ArrayIterator($this->params);
164
- }
165
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/helpers/SG_iCal_Parser.php DELETED
@@ -1,197 +0,0 @@
1
- <?php // BUILD: Remove line
2
-
3
- class SG_iCal_Parser {
4
- /**
5
- * Fetches $url and passes it on to be parsed
6
- * @param string $url
7
- * @param SG_iCal $ical
8
- */
9
- public static function Parse( $url, SG_iCal $ical ) {
10
- $content = self::Fetch( $url );
11
- $content = self::UnfoldLines($content);
12
- self::_Parse( $content, $ical );
13
- }
14
-
15
- /**
16
- * Passes a text string on to be parsed
17
- * @param string $content
18
- * @param SG_iCal $ical
19
- */
20
- public static function ParseString($content, SG_iCal $ical ) {
21
- $content = self::UnfoldLines($content);
22
- self::_Parse( $content, $ical );
23
- }
24
-
25
- /**
26
- * Fetches a resource and tries to make sure it's UTF8
27
- * encoded
28
- * @return string
29
- */
30
- protected static function Fetch( $resource ) {
31
- $is_utf8 = true;
32
-
33
- if( is_file( $resource ) ) {
34
- // The resource is a local file
35
- $content = file_get_contents($resource);
36
-
37
- if( ! self::_ValidUtf8( $content ) ) {
38
- // The file doesn't appear to be UTF8
39
- $is_utf8 = false;
40
- }
41
- } else {
42
- // The resource isn't local, so it's assumed to
43
- // be a URL
44
- $c = curl_init();
45
- curl_setopt($c, CURLOPT_URL, $resource);
46
- curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
47
- curl_setopt($c, CURLOPT_USERAGENT, 'PHP/'.PHP_VERSION);
48
- curl_setopt($c, CURLOPT_ENCODING, '');
49
- if( strstr( $resource, 'https' ) !== FALSE ) {
50
- curl_setopt($c, CURLOPT_SSLVERSION, 3);
51
- curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false);
52
- curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2);
53
- }
54
- curl_setopt($c, CURLOPT_COOKIESESSION, true);
55
- curl_setopt($c, CURLOPT_HEADER, true);
56
- if( !ini_get('safe_mode') ){
57
- curl_setopt($c, CURLOPT_FOLLOWLOCATION, true);
58
- }
59
- $content = curl_exec($c);
60
- $ct = curl_getinfo($c, CURLINFO_CONTENT_TYPE);
61
- $enc = preg_replace('/^.*charset=([-a-zA-Z0-9]+).*$/', '$1', $ct);
62
- if( ! self::_ValidUtf8( $content ) ) {
63
- // The data isn't utf-8
64
- $is_utf8 = false;
65
- }
66
- }
67
-
68
- if( !$is_utf8 ) {
69
- $content = utf8_encode($content);
70
- }
71
-
72
- return $content;
73
- }
74
-
75
- /**
76
- * Takes the string $content, and creates a array of iCal lines.
77
- * This includes unfolding multi-line entries into a single line.
78
- * @param $content string
79
- */
80
- protected static function UnfoldLines($content) {
81
- $data = array();
82
- $content = explode("\n", $content);
83
- for( $i=0; $i < count($content); $i++) {
84
- $line = rtrim($content[$i]);
85
- while( isset($content[$i+1]) && strlen($content[$i+1]) > 0 && ($content[$i+1]{0} == ' ' || $content[$i+1]{0} == "\t" )) {
86
- $line .= rtrim(substr($content[++$i],1));
87
- }
88
- $data[] = $line;
89
- }
90
- return $data;
91
- }
92
-
93
- /**
94
- * Parses the feed found in content and calls storeSection to store
95
- * parsed data
96
- * @param string $content
97
- * @param SG_iCal $ical
98
- */
99
- private static function _Parse( $content, SG_iCal $ical ) {
100
- $main_sections = array('vevent', 'vjournal', 'vtodo', 'vtimezone', 'vcalendar');
101
- $array_idents = array('exdate','rdate');
102
- $sections = array();
103
- $section = '';
104
- $current_data = array();
105
- foreach( $content AS $line ) {
106
- $line = new SG_iCal_Line($line);
107
- if( $line->isBegin() ) {
108
- // New block of data, $section = new block
109
- $section = strtolower($line->getData());
110
- $sections[] = strtolower($line->getData());
111
- } elseif( $line->isEnd() ) {
112
- // End of block of data ($removed = just ended block, $section = new top-block)
113
- $removed = array_pop($sections);
114
- $section = end($sections);
115
-
116
- if( array_search($removed, $main_sections) !== false ) {
117
- self::StoreSection( $removed, $current_data[$removed], $ical);
118
- $current_data[$removed] = array();
119
- }
120
- } else {
121
- // Data line
122
- foreach( $main_sections AS $s ) {
123
- // Loops though the main sections
124
- if( array_search($s, $sections) !== false ) {
125
- // This section is in the main section
126
- if( $section == $s ) {
127
- // It _is_ the main section else
128
- if (in_array($line->getIdent(), $array_idents))
129
- //exdate could appears more that once
130
- $current_data[$s][$line->getIdent()][] = $line;
131
- else {
132
- $current_data[$s][$line->getIdent()] = $line;
133
- }
134
- } else {
135
- // Sub section
136
- $current_data[$s][$section][$line->getIdent()] = $line;
137
- }
138
- break;
139
- }
140
- }
141
- }
142
- }
143
- $current_data = array();
144
- }
145
-
146
- /**
147
- * Stores the data in provided SG_iCal object
148
- * @param string $section eg 'vcalender', 'vevent' etc
149
- * @param string $data
150
- * @param SG_iCal $ical
151
- */
152
- protected static function storeSection( $section, $data, SG_iCal $ical ) {
153
- $data = SG_iCal_Factory::Factory($ical, $section, $data);
154
- switch( $section ) {
155
- case 'vcalendar':
156
- return $ical->setCalendarInfo( $data );
157
- case 'vevent':
158
- return $ical->addEvent( $data );
159
- case 'vjournal':
160
- case 'vtodo':
161
- return true; // TODO: Implement
162
- case 'vtimezone':
163
- return $ical->addTimeZone( $data );
164
- }
165
- }
166
-
167
- /**
168
- * This functions does some regexp checking to see if the value is
169
- * valid UTF-8.
170
- *
171
- * The function is from the book "Building Scalable Web Sites" by
172
- * Cal Henderson.
173
- *
174
- * @param string $data
175
- * @return bool
176
- */
177
- public static function _ValidUtf8( $data ) {
178
- $rx = '[\xC0-\xDF]([^\x80-\xBF]|$)';
179
- $rx .= '|[\xE0-\xEF].{0,1}([^\x80-\xBF]|$)';
180
- $rx .= '|[\xF0-\xF7].{0,2}([^\x80-\xBF]|$)';
181
- $rx .= '|[\xF8-\xFB].{0,3}([^\x80-\xBF]|$)';
182
- $rx .= '|[\xFC-\xFD].{0,4}([^\x80-\xBF]|$)';
183
- $rx .= '|[\xFE-\xFE].{0,5}([^\x80-\xBF]|$)';
184
- $rx .= '|[\x00-\x7F][\x80-\xBF]';
185
- $rx .= '|[\xC0-\xDF].[\x80-\xBF]';
186
- $rx .= '|[\xE0-\xEF]..[\x80-\xBF]';
187
- $rx .= '|[\xF0-\xF7]...[\x80-\xBF]';
188
- $rx .= '|[\xF8-\xFB]....[\x80-\xBF]';
189
- $rx .= '|[\xFC-\xFD].....[\x80-\xBF]';
190
- $rx .= '|[\xFE-\xFE]......[\x80-\xBF]';
191
- $rx .= '|^[\x80-\xBF]';
192
-
193
- return ( ! (bool) preg_match('!'.$rx.'!', $data) );
194
- }
195
- }
196
-
197
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/helpers/SG_iCal_Query.php DELETED
@@ -1,84 +0,0 @@
1
- <?php // BUILD: Remove line
2
-
3
- /**
4
- * A collection of functions to query the events in a calendar.
5
- *
6
- * @package SG_iCalReader
7
- * @author Morten Fangel (C) 2008
8
- * @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
9
- */
10
- class SG_iCal_Query {
11
- /**
12
- * Returns all events from the calendar between two timestamps
13
- *
14
- * Note that the events returned needs only slightly overlap.
15
- *
16
- * @param SG_iCalReader|array $ical The calendar to query
17
- * @param int $start
18
- * @param int $end
19
- * @return SG_iCal_VEvent[]
20
- */
21
- public static function Between( $ical, $start, $end ) {
22
- if( $ical instanceof SG_iCalReader ) {
23
- $ical = $ical->getEvents();
24
- }
25
- if( !is_array($ical) ) {
26
- throw new Exception('SG_iCal_Query::Between called with invalid input!');
27
- }
28
-
29
- $rtn = array();
30
- foreach( $ical AS $e ) {
31
- if( ($start <= $e->getStart() && $e->getStart() < $end)
32
- || ($start < $e->getRangeEnd() && $e->getRangeEnd() <= $end) ) {
33
- $rtn[] = $e;
34
- }
35
- }
36
- return $rtn;
37
- }
38
-
39
- /**
40
- * Returns all events from the calendar after a given timestamp
41
- *
42
- * @param SG_iCalReader|array $ical The calendar to query
43
- * @param int $start
44
- * @return SG_iCal_VEvent[]
45
- */
46
- public static function After( $ical, $start ) {
47
- if( $ical instanceof SG_iCalReader ) {
48
- $ical = $ical->getEvents();
49
- }
50
- if( !is_array($ical) ) {
51
- throw new Exception('SG_iCal_Query::After called with invalid input!');
52
- }
53
-
54
- $rtn = array();
55
- foreach( $ical AS $e ) {
56
- if($e->getStart() >= $start || $e->getRangeEnd() >= $start) {
57
- $rtn[] = $e;
58
- }
59
- }
60
- return $rtn;
61
- }
62
-
63
- /**
64
- * Sorts the events from the calendar after the specified column.
65
- * Column can be all valid entires that getProperty can return.
66
- * So stuff like uid, start, end, summary etc.
67
- * @param SG_iCalReader|array $ical The calendar to query
68
- * @param string $column
69
- * @return SG_iCal_VEvent[]
70
- */
71
- public static function Sort( $ical, $column ) {
72
- if( $ical instanceof SG_iCalReader ) {
73
- $ical = $ical->getEvents();
74
- }
75
- if( !is_array($ical) ) {
76
- throw new Exception('SG_iCal_Query::Sort called with invalid input!');
77
- }
78
-
79
- $cmp = create_function('$a, $b', 'return strcmp($a->getProperty("' . $column . '"), $b->getProperty("' . $column . '"));');
80
- usort($ical, $cmp);
81
- return $ical;
82
- }
83
- }
84
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/helpers/SG_iCal_Recurrence.php DELETED
@@ -1,223 +0,0 @@
1
- <?php // BUILD: Remove line
2
-
3
- /**
4
- * A wrapper for recurrence rules in iCalendar. Parses the given line and puts the
5
- * recurrence rules in the correct field of this object.
6
- *
7
- * See http://tools.ietf.org/html/rfc2445 for more information. Page 39 and onward contains more
8
- * information on the recurrence rules themselves. Page 116 and onward contains
9
- * some great examples which were often used for testing.
10
- *
11
- * @package SG_iCalReader
12
- * @author Steven Oxley
13
- * @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
14
- */
15
- class SG_iCal_Recurrence {
16
-
17
- public $rrule;
18
-
19
- protected $freq;
20
-
21
- protected $until;
22
- protected $count;
23
-
24
- protected $interval;
25
- protected $bysecond;
26
- protected $byminute;
27
- protected $byhour;
28
- protected $byday;
29
- protected $bymonthday;
30
- protected $byyearday;
31
- protected $byyearno;
32
- protected $bymonth;
33
- protected $bysetpos;
34
-
35
- protected $wkst;
36
-
37
- /**
38
- * A list of the properties that can have comma-separated lists for values.
39
- * @var array
40
- */
41
- protected $listProperties = array(
42
- 'bysecond', 'byminute', 'byhour', 'byday', 'bymonthday',
43
- 'byyearday', 'byyearno', 'bymonth', 'bysetpos'
44
- );
45
-
46
- /**
47
- * Creates an recurrence object with a passed in line. Parses the line.
48
- * @param object $line an SG_iCal_Line object which will be parsed to get the
49
- * desired information.
50
- */
51
- public function __construct(SG_iCal_Line $line) {
52
- $this->parseLine($line->getData());
53
- }
54
-
55
- /**
56
- * Parses an 'RRULE' line and sets the member variables of this object.
57
- * Expects a string that looks like this: 'FREQ=WEEKLY;INTERVAL=2;BYDAY=SU,TU,WE'
58
- * @param string $line the line to be parsed
59
- */
60
- protected function parseLine($line) {
61
- $this->rrule = $line;
62
-
63
- //split up the properties
64
- $recurProperties = explode(';', $line);
65
- $recur = array();
66
- //loop through the properties in the line and set their associated
67
- //member variables
68
- foreach ($recurProperties as $property) {
69
- if( empty( $property ) )
70
- continue;
71
-
72
- $nameAndValue = explode('=', $property);
73
-
74
- //need the lower-case name for setting the member variable
75
- $propertyName = strtolower($nameAndValue[0]);
76
- $propertyValue = $nameAndValue[1];
77
-
78
- //split up the list of values into an array (if it's a list)
79
- if (in_array($propertyName, $this->listProperties)) {
80
- $propertyValue = explode(',', $propertyValue);
81
- }
82
- $this->$propertyName = $propertyValue;
83
- }
84
- }
85
-
86
- /**
87
- * Set the $until member
88
- * @param mixed timestamp (int) / Valid DateTime format (string)
89
- */
90
- public function setUntil($ts) {
91
- if ( is_int($ts) )
92
- $dt = new DateTime('@'.$ts);
93
- else
94
- $dt = new DateTime($ts);
95
- $this->until = $dt->format('Ymd\THisO');
96
- }
97
-
98
- /**
99
- * Retrieves the desired member variable and returns it (if it's set)
100
- * @param string $member name of the member variable
101
- * @return mixed the variable value (if set), false otherwise
102
- */
103
- protected function getMember($member)
104
- {
105
- if (isset($this->$member)) {
106
- return $this->$member;
107
- }
108
- return false;
109
- }
110
-
111
- /**
112
- * Returns the frequency - corresponds to FREQ in RFC 2445.
113
- * @return mixed string if the member has been set, false otherwise
114
- */
115
- public function getFreq() {
116
- return $this->getMember('freq');
117
- }
118
-
119
- /**
120
- * Returns when the event will go until - corresponds to UNTIL in RFC 2445.
121
- * @return mixed string if the member has been set, false otherwise
122
- */
123
- public function getUntil() {
124
- return $this->getMember('until');
125
- }
126
-
127
- /**
128
- * Returns the count of the times the event will occur (should only appear if 'until'
129
- * does not appear) - corresponds to COUNT in RFC 2445.
130
- * @return mixed string if the member has been set, false otherwise
131
- */
132
- public function getCount() {
133
- return $this->getMember('count');
134
- }
135
-
136
- /**
137
- * Returns the interval - corresponds to INTERVAL in RFC 2445.
138
- * @return mixed string if the member has been set, false otherwise
139
- */
140
- public function getInterval() {
141
- return $this->getMember('interval');
142
- }
143
-
144
- /**
145
- * Returns the bysecond part of the event - corresponds to BYSECOND in RFC 2445.
146
- * @return mixed string if the member has been set, false otherwise
147
- */
148
- public function getBySecond() {
149
- return $this->getMember('bysecond');
150
- }
151
-
152
- /**
153
- * Returns the byminute information for the event - corresponds to BYMINUTE in RFC 2445.
154
- * @return mixed string if the member has been set, false otherwise
155
- */
156
- public function getByMinute() {
157
- return $this->getMember('byminute');
158
- }
159
-
160
- /**
161
- * Corresponds to BYHOUR in RFC 2445.
162
- * @return mixed string if the member has been set, false otherwise
163
- */
164
- public function getByHour() {
165
- return $this->getMember('byhour');
166
- }
167
-
168
- /**
169
- *Corresponds to BYDAY in RFC 2445.
170
- * @return mixed string if the member has been set, false otherwise
171
- */
172
- public function getByDay() {
173
- return $this->getMember('byday');
174
- }
175
-
176
- /**
177
- * Corresponds to BYMONTHDAY in RFC 2445.
178
- * @return mixed string if the member has been set, false otherwise
179
- */
180
- public function getByMonthDay() {
181
- return $this->getMember('bymonthday');
182
- }
183
-
184
- /**
185
- * Corresponds to BYYEARDAY in RFC 2445.
186
- * @return mixed string if the member has been set, false otherwise
187
- */
188
- public function getByYearDay() {
189
- return $this->getMember('byyearday');
190
- }
191
-
192
- /**
193
- * Corresponds to BYYEARNO in RFC 2445.
194
- * @return mixed string if the member has been set, false otherwise
195
- */
196
- public function getByYearNo() {
197
- return $this->getMember('byyearno');
198
- }
199
-
200
- /**
201
- * Corresponds to BYMONTH in RFC 2445.
202
- * @return mixed string if the member has been set, false otherwise
203
- */
204
- public function getByMonth() {
205
- return $this->getMember('bymonth');
206
- }
207
-
208
- /**
209
- * Corresponds to BYSETPOS in RFC 2445.
210
- * @return mixed string if the member has been set, false otherwise
211
- */
212
- public function getBySetPos() {
213
- return $this->getMember('bysetpos');
214
- }
215
-
216
- /**
217
- * Corresponds to WKST in RFC 2445.
218
- * @return mixed string if the member has been set, false otherwise
219
- */
220
- public function getWkst() {
221
- return $this->getMember('wkst');
222
- }
223
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/iCalcreator-2.10/iCalUtilityFunctions.class.php DELETED
@@ -1,1505 +0,0 @@
1
- <?php
2
- /**
3
- * iCalcreator class v2.10
4
- * copyright (c) 2007-2011 Kjell-Inge Gustafsson kigkonsult
5
- * www.kigkonsult.se/iCalcreator/index.php
6
- * ical@kigkonsult.se
7
- *
8
- * This library is free software; you can redistribute it and/or
9
- * modify it under the terms of the GNU Lesser General Public
10
- * License as published by the Free Software Foundation; either
11
- * version 2.1 of the License, or (at your option) any later version.
12
- *
13
- * This library is distributed in the hope that it will be useful,
14
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
- * Lesser General Public License for more details.
17
- *
18
- * You should have received a copy of the GNU Lesser General Public
19
- * License along with this library; if not, write to the Free Software
20
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
- */
22
- /**
23
- * moving all utility (static) functions to a utility class
24
- *
25
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
26
- * @since 2.6.22 - 2010-09-25
27
- *
28
- */
29
- class iCalUtilityFunctions {
30
- // Store the single instance of iCalUtilityFunctions
31
- private static $m_pInstance;
32
-
33
- // Private constructor to limit object instantiation to within the class
34
- private function __construct() {
35
- $m_pInstance = FALSE;
36
- }
37
-
38
- // Getter method for creating/returning the single instance of this class
39
- public static function getInstance() {
40
- if (!self::$m_pInstance)
41
- self::$m_pInstance = new iCalUtilityFunctions();
42
-
43
- return self::$m_pInstance;
44
- }
45
- /**
46
- * check a date(-time) for an opt. timezone and if it is a DATE-TIME or DATE
47
- *
48
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
49
- * @since 2.4.16 - 2008-10-25
50
- * @param array $date, date to check
51
- * @param int $parno, no of date parts (i.e. year, month.. .)
52
- * @return array $params, property parameters
53
- */
54
- public static function _chkdatecfg( $theDate, & $parno, & $params ) {
55
- if( isset( $params['TZID'] ))
56
- $parno = 6;
57
- elseif( isset( $params['VALUE'] ) && ( 'DATE' == $params['VALUE'] ))
58
- $parno = 3;
59
- else {
60
- if( isset( $params['VALUE'] ) && ( 'PERIOD' == $params['VALUE'] ))
61
- $parno = 7;
62
- if( is_array( $theDate )) {
63
- if( isset( $theDate['timestamp'] ))
64
- $tzid = ( isset( $theDate['tz'] )) ? $theDate['tz'] : null;
65
- else
66
- $tzid = ( isset( $theDate['tz'] )) ? $theDate['tz'] : ( 7 == count( $theDate )) ? end( $theDate ) : null;
67
- if( !empty( $tzid )) {
68
- $parno = 7;
69
- if( !iCalUtilityFunctions::_isOffset( $tzid ))
70
- $params['TZID'] = $tzid; // save only timezone
71
- }
72
- elseif( !$parno && ( 3 == count( $theDate )) &&
73
- ( isset( $params['VALUE'] ) && ( 'DATE' == $params['VALUE'] )))
74
- $parno = 3;
75
- else
76
- $parno = 6;
77
- }
78
- else { // string
79
- $date = trim( $theDate );
80
- if( 'Z' == substr( $date, -1 ))
81
- $parno = 7; // UTC DATE-TIME
82
- elseif((( 8 == strlen( $date ) && ctype_digit( $date )) || ( 11 >= strlen( $date ))) &&
83
- ( !isset( $params['VALUE'] ) || !in_array( $params['VALUE'], array( 'DATE-TIME', 'PERIOD' ))))
84
- $parno = 3; // DATE
85
- $date = iCalUtilityFunctions::_date_time_string( $date, $parno );
86
- if( !empty( $date['tz'] )) {
87
- $parno = 7;
88
- if( !iCalUtilityFunctions::_isOffset( $date['tz'] ))
89
- $params['TZID'] = $date['tz']; // save only timezone
90
- }
91
- elseif( empty( $parno ))
92
- $parno = 6;
93
- }
94
- if( isset( $params['TZID'] ))
95
- $parno = 6;
96
- }
97
- }
98
- /**
99
- * create (very simple) timezone and standard/daylight components
100
- *
101
- * Result when 'Europe/Stockholm' is used as timezone:
102
- *
103
- * BEGIN:VTIMEZONE
104
- * TZID:Europe/Stockholm
105
- * BEGIN:STANDARD
106
- * DTSTART:20101031T020000
107
- * TZOFFSETFROM:+0200
108
- * TZOFFSETTO:+0100
109
- * RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
110
- * TZNAME:CET
111
- * END:STANDARD
112
- * BEGIN:DAYLIGHT
113
- * DTSTART:20100328T030000
114
- * TZOFFSETFROM:+0100
115
- * TZOFFSETTO:+0200
116
- * RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
117
- * TZNAME:CEST
118
- * END:DAYLIGHT
119
- * END:VTIMEZONE
120
- *
121
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
122
- * @since 2.9.2 - 2011-05-30
123
- * @param object $calendar, reference to an iCalcreator calendar instance
124
- * @param string $timezone, a PHP5 (DateTimeZone) valid timezone
125
- * @param array $xProp, *[x-propName => x-propValue], optional
126
- * @return bool
127
- */
128
- public static function createTimezone( & $calendar, $timezone, $xProp=array() ) {
129
- if( !class_exists( 'DateTimeZone' ))
130
- return FALSE;
131
- if( empty( $timezone ))
132
- return FALSE;
133
- try {
134
- $dtz = new DateTimeZone( $timezone );
135
- $transitions = $dtz->getTransitions();
136
- $stdDTSTART = $stdTZOFFSETTO = $stdTZOFFSETFROM = $stdTZNAME = $dlghtDTSTART = $dlghtTZOFFSETTO = $dlghtTZOFFSETFROM = $dlghtTZNAME = FALSE;
137
- foreach( $transitions as $trans ) {
138
- if( substr( $trans['time'], 0, 4 ) > ( date( 'Y' ) - 1 ))
139
- break;
140
- if( $trans['isdst'] !== TRUE ) {
141
- $stdDTSTART = $trans['time'];
142
- $stdTZOFFSETTO = $dlghtTZOFFSETFROM = iCalUtilityFunctions::offsetSec2His( $trans['offset'] );
143
- $stdTZNAME = $trans['abbr'];
144
- }
145
- else {
146
- $dlghtDTSTART = $trans['time'];
147
- $dlghtTZOFFSETTO = $stdTZOFFSETFROM = iCalUtilityFunctions::offsetSec2His( $trans['offset'] );
148
- $dlghtTZNAME = $trans['abbr'];
149
- }
150
- }
151
- if( $stdDTSTART && $stdTZOFFSETTO && $stdTZOFFSETFROM && $stdTZNAME && $dlghtDTSTART && $dlghtTZOFFSETTO && $dlghtTZOFFSETFROM && $dlghtTZNAME ) {
152
- $tz = & $calendar->newComponent( 'vtimezone' );
153
- $tz->setproperty( 'tzid', $timezone );
154
- if( !empty( $xProp )) {
155
- foreach( $xProp as $xPropName => $xPropValue )
156
- if( 'x-' == strtolower( substr( $xPropName, 0, 2 )))
157
- $tz->setproperty( $xPropName, $xPropValue );
158
- }
159
- $std = & $tz->newComponent( 'standard' );
160
- $std->setProperty( 'dtstart', $stdDTSTART );
161
- $std->setProperty( 'tzname', $stdTZNAME );
162
- $std->setProperty( 'tzoffsetto', $stdTZOFFSETTO );
163
- $std->setProperty( 'tzoffsetfrom', $stdTZOFFSETFROM );
164
- $std->setProperty( 'RRULE', array( 'FREQ' => 'YEARLY', 'BYDAY' => array( '-1', 'DAY' => 'SU' ), 'BYMONTH' => 10 ));
165
- $dlght = & $tz->newComponent( 'daylight' );
166
- $dlght->setProperty( 'dtstart', $dlghtDTSTART );
167
- $dlght->setProperty( 'tzname', $dlghtTZNAME );
168
- $dlght->setProperty( 'tzoffsetto', $dlghtTZOFFSETTO );
169
- $dlght->setProperty( 'tzoffsetfrom', $dlghtTZOFFSETFROM );
170
- $dlght->setProperty( 'RRULE', array( 'FREQ' => 'YEARLY', 'BYDAY' => array( '-1', 'DAY' => 'SU' ), 'BYMONTH' => 3 ));
171
- }
172
- }
173
- catch( Exception $e ) {
174
- return FALSE;
175
- }
176
- return TRUE;
177
- }
178
- /**
179
- * convert date/datetime to timestamp
180
- *
181
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
182
- * @since 2.4.8 - 2008-10-30
183
- * @param array $datetime datetime/(date)
184
- * @param string $tz timezone
185
- * @return timestamp
186
- */
187
- public static function _date2timestamp( $datetime, $tz=null ) {
188
- $output = null;
189
- if( !isset( $datetime['hour'] )) $datetime['hour'] = '0';
190
- if( !isset( $datetime['min'] )) $datetime['min'] = '0';
191
- if( !isset( $datetime['sec'] )) $datetime['sec'] = '0';
192
- foreach( $datetime as $dkey => $dvalue ) {
193
- if( 'tz' != $dkey )
194
- $datetime[$dkey] = (integer) $dvalue;
195
- }
196
- if( $tz )
197
- $datetime['tz'] = $tz;
198
- $offset = ( isset( $datetime['tz'] ) && ( '' < trim ( $datetime['tz'] ))) ? iCalUtilityFunctions::_tz2offset( $datetime['tz'] ) : 0;
199
- $output = mktime( $datetime['hour'], $datetime['min'], ($datetime['sec'] + $offset), $datetime['month'], $datetime['day'], $datetime['year'] );
200
- return $output;
201
- }
202
- /**
203
- * ensures internal date-time/date format for input date-time/date in array format
204
- *
205
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
206
- * @since 0.3.0 - 2006-08-15
207
- * @param array $datetime
208
- * @param int $parno optional, default FALSE
209
- * @return array
210
- */
211
- public static function _date_time_array( $datetime, $parno=FALSE ) {
212
- $output = array();
213
- foreach( $datetime as $dateKey => $datePart ) {
214
- switch ( $dateKey ) {
215
- case '0': case 'year': $output['year'] = $datePart; break;
216
- case '1': case 'month': $output['month'] = $datePart; break;
217
- case '2': case 'day': $output['day'] = $datePart; break;
218
- }
219
- if( 3 != $parno ) {
220
- switch ( $dateKey ) {
221
- case '0':
222
- case '1':
223
- case '2': break;
224
- case '3': case 'hour': $output['hour'] = $datePart; break;
225
- case '4': case 'min' : $output['min'] = $datePart; break;
226
- case '5': case 'sec' : $output['sec'] = $datePart; break;
227
- case '6': case 'tz' : $output['tz'] = $datePart; break;
228
- }
229
- }
230
- }
231
- if( 3 != $parno ) {
232
- if( !isset( $output['hour'] ))
233
- $output['hour'] = 0;
234
- if( !isset( $output['min'] ))
235
- $output['min'] = 0;
236
- if( !isset( $output['sec'] ))
237
- $output['sec'] = 0;
238
- }
239
- return $output;
240
- }
241
- /**
242
- * ensures internal date-time/date format for input date-time/date in string fromat
243
- *
244
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
245
- * @since 2.6.35 - 2010-12-03
246
- * @param array $datetime
247
- * @param int $parno optional, default FALSE
248
- * @return array
249
- */
250
- public static function _date_time_string( $datetime, $parno=FALSE ) {
251
- $datetime = (string) trim( $datetime );
252
- $tz = null;
253
- $len = strlen( $datetime ) - 1;
254
- if( 'Z' == substr( $datetime, -1 )) {
255
- $tz = 'Z';
256
- $datetime = trim( substr( $datetime, 0, $len ));
257
- }
258
- elseif( ( ctype_digit( substr( $datetime, -2, 2 ))) && // time or date
259
- ( '-' == substr( $datetime, -3, 1 )) ||
260
- ( ':' == substr( $datetime, -3, 1 )) ||
261
- ( '.' == substr( $datetime, -3, 1 ))) {
262
- $continue = TRUE;
263
- }
264
- elseif( ( ctype_digit( substr( $datetime, -4, 4 ))) && // 4 pos offset
265
- ( ' +' == substr( $datetime, -6, 2 )) ||
266
- ( ' -' == substr( $datetime, -6, 2 ))) {
267
- $tz = substr( $datetime, -5, 5 );
268
- $datetime = substr( $datetime, 0, ($len - 5));
269
- }
270
- elseif( ( ctype_digit( substr( $datetime, -6, 6 ))) && // 6 pos offset
271
- ( ' +' == substr( $datetime, -8, 2 )) ||
272
- ( ' -' == substr( $datetime, -8, 2 ))) {
273
- $tz = substr( $datetime, -7, 7 );
274
- $datetime = substr( $datetime, 0, ($len - 7));
275
- }
276
- elseif( ( 6 < $len ) && ( ctype_digit( substr( $datetime, -6, 6 )))) {
277
- $continue = TRUE;
278
- }
279
- elseif( 'T' == substr( $datetime, -7, 1 )) {
280
- $continue = TRUE;
281
- }
282
- else {
283
- $cx = $tx = 0; // 19970415T133000 US-Eastern
284
- for( $cx = -1; $cx > ( 9 - $len ); $cx-- ) {
285
- $char = substr( $datetime, $cx, 1 );
286
- if(( ' ' == $char) || ctype_digit( $char))
287
- break; // if exists, tz ends here.. . ?
288
- else
289
- $tx--; // tz length counter
290
- }
291
- if( 0 > $tx ) {
292
- $tz = substr( $datetime, $tx );
293
- $datetime = trim( substr( $datetime, 0, $len + $tx + 1 ));
294
- }
295
- }
296
- if( 0 < substr_count( $datetime, '-' )) {
297
- $datetime = str_replace( '-', '/', $datetime );
298
- }
299
- elseif( ctype_digit( substr( $datetime, 0, 8 )) &&
300
- ( 'T' == substr( $datetime, 8, 1 )) &&
301
- ctype_digit( substr( $datetime, 9, 6 ))) {
302
- $datetime = substr( $datetime, 4, 2 )
303
- .'/'.substr( $datetime, 6, 2 )
304
- .'/'.substr( $datetime, 0, 4 )
305
- .' '.substr( $datetime, 9, 2 )
306
- .':'.substr( $datetime, 11, 2 )
307
- .':'.substr( $datetime, 13);
308
- }
309
- $datestring = date( 'Y-m-d H:i:s', strtotime( $datetime ));
310
- $tz = trim( $tz );
311
- $output = array();
312
- $output['year'] = substr( $datestring, 0, 4 );
313
- $output['month'] = substr( $datestring, 5, 2 );
314
- $output['day'] = substr( $datestring, 8, 2 );
315
- if(( 6 == $parno ) || ( 7 == $parno ) || ( !$parno && ( 'Z' == $tz ))) {
316
- $output['hour'] = substr( $datestring, 11, 2 );
317
- $output['min'] = substr( $datestring, 14, 2 );
318
- $output['sec'] = substr( $datestring, 17, 2 );
319
- if( !empty( $tz ))
320
- $output['tz'] = $tz;
321
- }
322
- elseif( 3 != $parno ) {
323
- if(( '00' < substr( $datestring, 11, 2 )) ||
324
- ( '00' < substr( $datestring, 14, 2 )) ||
325
- ( '00' < substr( $datestring, 17, 2 ))) {
326
- $output['hour'] = substr( $datestring, 11, 2 );
327
- $output['min'] = substr( $datestring, 14, 2 );
328
- $output['sec'] = substr( $datestring, 17, 2 );
329
- }
330
- if( !empty( $tz ))
331
- $output['tz'] = $tz;
332
- }
333
- return $output;
334
- }
335
- /**
336
- * convert local startdate/enddate (Ymd[His]) to duration array
337
- *
338
- * uses this component dates if missing input dates
339
- *
340
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
341
- * @since 2.6.11 - 2010-10-21
342
- * @param array $startdate
343
- * @param array $duration
344
- * @return array duration
345
- */
346
- function _date2duration( $startdate, $enddate ) {
347
- $startWdate = mktime( 0, 0, 0, $startdate['month'], $startdate['day'], $startdate['year'] );
348
- $endWdate = mktime( 0, 0, 0, $enddate['month'], $enddate['day'], $enddate['year'] );
349
- $wduration = $endWdate - $startWdate;
350
- $dur = array();
351
- $dur['week'] = (int) floor( $wduration / ( 7 * 24 * 60 * 60 ));
352
- $wduration = $wduration % ( 7 * 24 * 60 * 60 );
353
- $dur['day'] = (int) floor( $wduration / ( 24 * 60 * 60 ));
354
- $wduration = $wduration % ( 24 * 60 * 60 );
355
- $dur['hour'] = (int) floor( $wduration / ( 60 * 60 ));
356
- $wduration = $wduration % ( 60 * 60 );
357
- $dur['min'] = (int) floor( $wduration / ( 60 ));
358
- $dur['sec'] = (int) $wduration % ( 60 );
359
- return $dur;
360
- }
361
- /**
362
- * ensures internal duration format for input in array format
363
- *
364
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
365
- * @since 2.1.1 - 2007-06-24
366
- * @param array $duration
367
- * @return array
368
- */
369
- public static function _duration_array( $duration ) {
370
- $output = array();
371
- if( is_array( $duration ) &&
372
- ( 1 == count( $duration )) &&
373
- isset( $duration['sec'] ) &&
374
- ( 60 < $duration['sec'] )) {
375
- $durseconds = $duration['sec'];
376
- $output['week'] = floor( $durseconds / ( 60 * 60 * 24 * 7 ));
377
- $durseconds = $durseconds % ( 60 * 60 * 24 * 7 );
378
- $output['day'] = floor( $durseconds / ( 60 * 60 * 24 ));
379
- $durseconds = $durseconds % ( 60 * 60 * 24 );
380
- $output['hour'] = floor( $durseconds / ( 60 * 60 ));
381
- $durseconds = $durseconds % ( 60 * 60 );
382
- $output['min'] = floor( $durseconds / ( 60 ));
383
- $output['sec'] = ( $durseconds % ( 60 ));
384
- }
385
- else {
386
- foreach( $duration as $durKey => $durValue ) {
387
- if( empty( $durValue )) continue;
388
- switch ( $durKey ) {
389
- case '0': case 'week': $output['week'] = $durValue; break;
390
- case '1': case 'day': $output['day'] = $durValue; break;
391
- case '2': case 'hour': $output['hour'] = $durValue; break;
392
- case '3': case 'min': $output['min'] = $durValue; break;
393
- case '4': case 'sec': $output['sec'] = $durValue; break;
394
- }
395
- }
396
- }
397
- if( isset( $output['week'] ) && ( 0 < $output['week'] )) {
398
- unset( $output['day'], $output['hour'], $output['min'], $output['sec'] );
399
- return $output;
400
- }
401
- unset( $output['week'] );
402
- if( empty( $output['day'] ))
403
- unset( $output['day'] );
404
- if ( isset( $output['hour'] ) || isset( $output['min'] ) || isset( $output['sec'] )) {
405
- if( !isset( $output['hour'] )) $output['hour'] = 0;
406
- if( !isset( $output['min'] )) $output['min'] = 0;
407
- if( !isset( $output['sec'] )) $output['sec'] = 0;
408
- if(( 0 == $output['hour'] ) && ( 0 == $output['min'] ) && ( 0 == $output['sec'] ))
409
- unset( $output['hour'], $output['min'], $output['sec'] );
410
- }
411
- return $output;
412
- }
413
- /**
414
- * ensures internal duration format for input in string format
415
- *
416
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
417
- * @since 2.0.5 - 2007-03-14
418
- * @param string $duration
419
- * @return array
420
- */
421
- public static function _duration_string( $duration ) {
422
- $duration = (string) trim( $duration );
423
- while( 'P' != strtoupper( substr( $duration, 0, 1 ))) {
424
- if( 0 < strlen( $duration ))
425
- $duration = substr( $duration, 1 );
426
- else
427
- return false; // no leading P !?!?
428
- }
429
- $duration = substr( $duration, 1 ); // skip P
430
- $duration = str_replace ( 't', 'T', $duration );
431
- $duration = str_replace ( 'T', '', $duration );
432
- $output = array();
433
- $val = null;
434
- for( $ix=0; $ix < strlen( $duration ); $ix++ ) {
435
- switch( strtoupper( substr( $duration, $ix, 1 ))) {
436
- case 'W':
437
- $output['week'] = $val;
438
- $val = null;
439
- break;
440
- case 'D':
441
- $output['day'] = $val;
442
- $val = null;
443
- break;
444
- case 'H':
445
- $output['hour'] = $val;
446
- $val = null;
447
- break;
448
- case 'M':
449
- $output['min'] = $val;
450
- $val = null;
451
- break;
452
- case 'S':
453
- $output['sec'] = $val;
454
- $val = null;
455
- break;
456
- default:
457
- if( !ctype_digit( substr( $duration, $ix, 1 )))
458
- return false; // unknown duration control character !?!?
459
- else
460
- $val .= substr( $duration, $ix, 1 );
461
- }
462
- }
463
- return iCalUtilityFunctions::_duration_array( $output );
464
- }
465
- /**
466
- * convert duration to date in array format
467
- *
468
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
469
- * @since 2.8.7 - 2011-03-03
470
- * @param array $startdate
471
- * @param array $duration
472
- * @return array, date format
473
- */
474
- function _duration2date( $startdate=null, $duration=null ) {
475
- if( empty( $startdate )) return FALSE;
476
- if( empty( $duration )) return FALSE;
477
- $dateOnly = ( isset( $startdate['hour'] ) || isset( $startdate['min'] ) || isset( $startdate['sec'] )) ? FALSE : TRUE;
478
- $startdate['hour'] = ( isset( $startdate['hour'] )) ? $startdate['hour'] : 0;
479
- $startdate['min'] = ( isset( $startdate['min'] )) ? $startdate['min'] : 0;
480
- $startdate['sec'] = ( isset( $startdate['sec'] )) ? $startdate['sec'] : 0;
481
- $dtend = 0;
482
- if( isset( $duration['week'] ))
483
- $dtend += ( $duration['week'] * 7 * 24 * 60 * 60 );
484
- if( isset( $duration['day'] ))
485
- $dtend += ( $duration['day'] * 24 * 60 * 60 );
486
- if( isset( $duration['hour'] ))
487
- $dtend += ( $duration['hour'] * 60 *60 );
488
- if( isset( $duration['min'] ))
489
- $dtend += ( $duration['min'] * 60 );
490
- if( isset( $duration['sec'] ))
491
- $dtend += $duration['sec'];
492
- $dtend = mktime( $startdate['hour'], $startdate['min'], ( $startdate['sec'] + $dtend ), $startdate['month'], $startdate['day'], $startdate['year'] );
493
- $dtend2 = array();
494
- $dtend2['year'] = date('Y', $dtend );
495
- $dtend2['month'] = date('m', $dtend );
496
- $dtend2['day'] = date('d', $dtend );
497
- $dtend2['hour'] = date('H', $dtend );
498
- $dtend2['min'] = date('i', $dtend );
499
- $dtend2['sec'] = date('s', $dtend );
500
- if( isset( $startdate['tz'] ))
501
- $dtend2['tz'] = $startdate['tz'];
502
- if( $dateOnly && (( 0 == $dtend2['hour'] ) && ( 0 == $dtend2['min'] ) && ( 0 == $dtend2['sec'] )))
503
- unset( $dtend2['hour'], $dtend2['min'], $dtend2['sec'] );
504
- return $dtend2;
505
- }
506
- /**
507
- * if not preSet, if exist, remove key with expected value from array and return hit value else return elseValue
508
- *
509
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
510
- * @since 2.4.16 - 2008-11-08
511
- * @param array $array
512
- * @param string $expkey, expected key
513
- * @param string $expval, expected value
514
- * @param int $hitVal optional, return value if found
515
- * @param int $elseVal optional, return value if not found
516
- * @param int $preSet optional, return value if already preset
517
- * @return int
518
- */
519
- public static function _existRem( &$array, $expkey, $expval=FALSE, $hitVal=null, $elseVal=null, $preSet=null ) {
520
- if( $preSet )
521
- return $preSet;
522
- if( !is_array( $array ) || ( 0 == count( $array )))
523
- return $elseVal;
524
- foreach( $array as $key => $value ) {
525
- if( strtoupper( $expkey ) == strtoupper( $key )) {
526
- if( !$expval || ( strtoupper( $expval ) == strtoupper( $array[$key] ))) {
527
- unset( $array[$key] );
528
- return $hitVal;
529
- }
530
- }
531
- }
532
- return $elseVal;
533
- }
534
- /**
535
- * creates formatted output for calendar component property data value type date/date-time
536
- *
537
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
538
- * @since 2.4.8 - 2008-10-30
539
- * @param array $datetime
540
- * @param int $parno, optional, default 6
541
- * @return string
542
- */
543
- public static function _format_date_time( $datetime, $parno=6 ) {
544
- if( !isset( $datetime['year'] ) &&
545
- !isset( $datetime['month'] ) &&
546
- !isset( $datetime['day'] ) &&
547
- !isset( $datetime['hour'] ) &&
548
- !isset( $datetime['min'] ) &&
549
- !isset( $datetime['sec'] ))
550
- return ;
551
- $output = null;
552
- // if( !isset( $datetime['day'] )) { $o=''; foreach($datetime as $k=>$v) {if(is_array($v)) $v=implode('-',$v);$o.=" $k=>$v";} echo " day SAKNAS : $o <br />\n"; }
553
- foreach( $datetime as $dkey => & $dvalue )
554
- if( 'tz' != $dkey ) $dvalue = (integer) $dvalue;
555
- $output = date('Ymd', mktime( 0, 0, 0, $datetime['month'], $datetime['day'], $datetime['year']));
556
- if( isset( $datetime['hour'] ) ||
557
- isset( $datetime['min'] ) ||
558
- isset( $datetime['sec'] ) ||
559
- isset( $datetime['tz'] )) {
560
- if( isset( $datetime['tz'] ) &&
561
- !isset( $datetime['hour'] ))
562
- $datetime['hour'] = 0;
563
- if( isset( $datetime['hour'] ) &&
564
- !isset( $datetime['min'] ))
565
- $datetime['min'] = 0;
566
- if( isset( $datetime['hour'] ) &&
567
- isset( $datetime['min'] ) &&
568
- !isset( $datetime['sec'] ))
569
- $datetime['sec'] = 0;
570
- $date = mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year']);
571
- $output .= date('\THis', $date );
572
- if( isset( $datetime['tz'] ) && ( '' < trim ( $datetime['tz'] ))) {
573
- $datetime['tz'] = trim( $datetime['tz'] );
574
- if( 'Z' == $datetime['tz'] )
575
- $output .= 'Z';
576
- $offset = iCalUtilityFunctions::_tz2offset( $datetime['tz'] );
577
- if( 0 != $offset ) {
578
- $date = mktime( $datetime['hour'], $datetime['min'], ($datetime['sec'] + $offset), $datetime['month'], $datetime['day'], $datetime['year']);
579
- $output = date( 'Ymd\THis\Z', $date );
580
- }
581
- }
582
- elseif( 7 == $parno )
583
- $output .= 'Z';
584
- }
585
- return $output;
586
- }
587
- /**
588
- * creates formatted output for calendar component property data value type duration
589
- *
590
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
591
- * @since 2.9.9 - 2011-06-17
592
- * @param array $duration ( week, day, hour, min, sec )
593
- * @return string
594
- */
595
- public static function _format_duration( $duration ) {
596
- if( isset( $duration['week'] ) ||
597
- isset( $duration['day'] ) ||
598
- isset( $duration['hour'] ) ||
599
- isset( $duration['min'] ) ||
600
- isset( $duration['sec'] ))
601
- $ok = TRUE;
602
- else
603
- return;
604
- if( isset( $duration['week'] ) && ( 0 < $duration['week'] ))
605
- return 'P'.$duration['week'].'W';
606
- $output = 'P';
607
- if( isset($duration['day'] ) && ( 0 < $duration['day'] ))
608
- $output .= $duration['day'].'D';
609
- if(( isset( $duration['hour']) && ( 0 < $duration['hour'] )) ||
610
- ( isset( $duration['min']) && ( 0 < $duration['min'] )) ||
611
- ( isset( $duration['sec']) && ( 0 < $duration['sec'] )))
612
- $output .= 'T';
613
- $output .= ( isset( $duration['hour']) && ( 0 < $duration['hour'] )) ? $duration['hour'].'H' : '';
614
- $output .= ( isset( $duration['min']) && ( 0 < $duration['min'] )) ? $duration['min']. 'M' : '';
615
- $output .= ( isset( $duration['sec']) && ( 0 < $duration['sec'] )) ? $duration['sec']. 'S' : '';
616
- if( 'P' == $output )
617
- $output = 'PT0S';
618
- return $output;
619
- }
620
- /**
621
- * checks if input array contains a date
622
- *
623
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
624
- * @since 2.4.16 - 2008-10-25
625
- * @param array $input
626
- * @return bool
627
- */
628
- public static function _isArrayDate( $input ) {
629
- if( isset( $input['week'] ) || ( !in_array( count( $input ), array( 3, 6, 7 ))))
630
- return FALSE;
631
- if( 7 == count( $input ))
632
- return TRUE;
633
- if( isset( $input['year'] ) && isset( $input['month'] ) && isset( $input['day'] ))
634
- return checkdate( (int) $input['month'], (int) $input['day'], (int) $input['year'] );
635
- if( isset( $input['day'] ) || isset( $input['hour'] ) || isset( $input['min'] ) || isset( $input['sec'] ))
636
- return FALSE;
637
- if( in_array( 0, $input ))
638
- return FALSE;
639
- if(( 1970 > $input[0] ) || ( 12 < $input[1] ) || ( 31 < $input[2] ))
640
- return FALSE;
641
- if(( isset( $input[0] ) && isset( $input[1] ) && isset( $input[2] )) &&
642
- checkdate( (int) $input[1], (int) $input[2], (int) $input[0] ))
643
- return TRUE;
644
- $input = iCalUtilityFunctions::_date_time_string( $input[1].'/'.$input[2].'/'.$input[0], 3 ); // m - d - Y
645
- if( isset( $input['year'] ) && isset( $input['month'] ) && isset( $input['day'] ))
646
- return checkdate( (int) $input['month'], (int) $input['day'], (int) $input['year'] );
647
- return FALSE;
648
- }
649
- /**
650
- * checks if input array contains a timestamp date
651
- *
652
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
653
- * @since 2.4.16 - 2008-10-18
654
- * @param array $input
655
- * @return bool
656
- */
657
- public static function _isArrayTimestampDate( $input ) {
658
- return ( is_array( $input ) && isset( $input['timestamp'] )) ? TRUE : FALSE ;
659
- }
660
- /**
661
- * controll if input string contains trailing UTC offset
662
- *
663
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
664
- * @since 2.4.16 - 2008-10-19
665
- * @param string $input
666
- * @return bool
667
- */
668
- public static function _isOffset( $input ) {
669
- $input = trim( (string) $input );
670
- if( 'Z' == substr( $input, -1 ))
671
- return TRUE;
672
- elseif(( 5 <= strlen( $input )) &&
673
- ( in_array( substr( $input, -5, 1 ), array( '+', '-' ))) &&
674
- ( '0000' < substr( $input, -4 )) && ( '9999' >= substr( $input, -4 )))
675
- return TRUE;
676
- elseif(( 7 <= strlen( $input )) &&
677
- ( in_array( substr( $input, -7, 1 ), array( '+', '-' ))) &&
678
- ( '000000' < substr( $input, -6 )) && ( '999999' >= substr( $input, -6 )))
679
- return TRUE;
680
- return FALSE;
681
-
682
- }
683
- /**
684
- * transform offset in seconds to [-/+]hhmm[ss]
685
- *
686
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
687
- * @since 2011-05-02
688
- * @param string $seconds
689
- * @return string
690
- */
691
- public static function offsetSec2His( $seconds ) {
692
- if( '-' == substr( $seconds, 0, 1 )) {
693
- $prefix = '-';
694
- $seconds = substr( $seconds, 1 );
695
- }
696
- elseif( '+' == substr( $seconds, 0, 1 )) {
697
- $prefix = '+';
698
- $seconds = substr( $seconds, 1 );
699
- }
700
- else
701
- $prefix = '+';
702
- $output = '';
703
- $hour = (int) floor( $seconds / 3600 );
704
- if( 10 > $hour )
705
- $hour = '0'.$hour;
706
- $seconds = $seconds % 3600;
707
- $min = (int) floor( $seconds / 60 );
708
- if( 10 > $min )
709
- $min = '0'.$min;
710
- $output = $hour.$min;
711
- $seconds = $seconds % 60;
712
- if( 0 < $seconds) {
713
- if( 9 < $seconds)
714
- $output .= $seconds;
715
- else
716
- $output .= '0'.$seconds;
717
- }
718
- return $prefix.$output;
719
- }
720
- /**
721
- * remakes a recur pattern to an array of dates
722
- *
723
- * if missing, UNTIL is set 1 year from startdate (emergency break)
724
- *
725
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
726
- * @since 2.9.10 - 2011-07-07
727
- * @param array $result, array to update, array([timestamp] => timestamp)
728
- * @param array $recur, pattern for recurrency (only value part, params ignored)
729
- * @param array $wdate, component start date
730
- * @param array $startdate, start date
731
- * @param array $enddate, optional
732
- * @return array of recurrence (start-)dates as index
733
- * @todo BYHOUR, BYMINUTE, BYSECOND, ev. BYSETPOS due to ambiguity, WEEKLY at year end/start
734
- */
735
- public static function _recur2date( & $result, $recur, $wdate, $startdate, $enddate=FALSE ) {
736
- foreach( $wdate as $k => $v ) if( ctype_digit( $v )) $wdate[$k] = (int) $v;
737
- $wdateStart = $wdate;
738
- $wdatets = iCalUtilityFunctions::_date2timestamp( $wdate );
739
- $startdatets = iCalUtilityFunctions::_date2timestamp( $startdate );
740
- if( !$enddate ) {
741
- $enddate = $startdate;
742
- $enddate['year'] += 1;
743
- }
744
- // echo "recur __in_ comp start ".implode('-',$wdate)." period start ".implode('-',$startdate)." period end ".implode('-',$enddate)."<br />\n";print_r($recur);echo "<br />\n";//test###
745
- $endDatets = iCalUtilityFunctions::_date2timestamp( $enddate ); // fix break
746
- if( !isset( $recur['COUNT'] ) && !isset( $recur['UNTIL'] ))
747
- $recur['UNTIL'] = $enddate; // create break
748
- if( isset( $recur['UNTIL'] )) {
749
- $tdatets = iCalUtilityFunctions::_date2timestamp( $recur['UNTIL'] );
750
- if( $endDatets > $tdatets ) {
751
- $endDatets = $tdatets; // emergency break
752
- $enddate = iCalUtilityFunctions::_timestamp2date( $endDatets, 6 );
753
- }
754
- else
755
- $recur['UNTIL'] = iCalUtilityFunctions::_timestamp2date( $endDatets, 6 );
756
- }
757
- if( $wdatets > $endDatets ) {
758
- // echo "recur out of date ".implode('-',iCalUtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
759
- return array(); // nothing to do.. .
760
- }
761
- if( !isset( $recur['FREQ'] )) // "MUST be specified.. ."
762
- $recur['FREQ'] = 'DAILY'; // ??
763
- $wkst = ( isset( $recur['WKST'] ) && ( 'SU' == $recur['WKST'] )) ? 24*60*60 : 0; // ??
764
- $weekStart = (int) date( 'W', ( $wdatets + $wkst ));
765
- if( !isset( $recur['INTERVAL'] ))
766
- $recur['INTERVAL'] = 1;
767
- $countcnt = ( !isset( $recur['BYSETPOS'] )) ? 1 : 0; // DTSTART counts as the first occurrence
768
- /* find out how to step up dates and set index for interval count */
769
- $step = array();
770
- if( 'YEARLY' == $recur['FREQ'] )
771
- $step['year'] = 1;
772
- elseif( 'MONTHLY' == $recur['FREQ'] )
773
- $step['month'] = 1;
774
- elseif( 'WEEKLY' == $recur['FREQ'] )
775
- $step['day'] = 7;
776
- else
777
- $step['day'] = 1;
778
- if( isset( $step['year'] ) && isset( $recur['BYMONTH'] ))
779
- $step = array( 'month' => 1 );
780
- if( empty( $step ) && isset( $recur['BYWEEKNO'] )) // ??
781
- $step = array( 'day' => 7 );
782
- if( isset( $recur['BYYEARDAY'] ) || isset( $recur['BYMONTHDAY'] ) || isset( $recur['BYDAY'] ))
783
- $step = array( 'day' => 1 );
784
- $intervalarr = array();
785
- if( 1 < $recur['INTERVAL'] ) {
786
- $intervalix = iCalUtilityFunctions::_recurIntervalIx( $recur['FREQ'], $wdate, $wkst );
787
- $intervalarr = array( $intervalix => 0 );
788
- }
789
- if( isset( $recur['BYSETPOS'] )) { // save start date + weekno
790
- $bysetposymd1 = $bysetposymd2 = $bysetposw1 = $bysetposw2 = array();
791
- // echo "bysetposXold_start=$bysetposYold $bysetposMold $bysetposDold<br />\n"; // test ###
792
- if( is_array( $recur['BYSETPOS'] )) {
793
- foreach( $recur['BYSETPOS'] as $bix => $bval )
794
- $recur['BYSETPOS'][$bix] = (int) $bval;
795
- }
796
- else
797
- $recur['BYSETPOS'] = array( (int) $recur['BYSETPOS'] );
798
- if( 'YEARLY' == $recur['FREQ'] ) {
799
- $wdate['month'] = $wdate['day'] = 1; // start from beginning of year
800
- $wdatets = iCalUtilityFunctions::_date2timestamp( $wdate );
801
- iCalUtilityFunctions::_stepdate( $enddate, $endDatets, array( 'year' => 1 )); // make sure to count whole last year
802
- }
803
- elseif( 'MONTHLY' == $recur['FREQ'] ) {
804
- $wdate['day'] = 1; // start from beginning of month
805
- $wdatets = iCalUtilityFunctions::_date2timestamp( $wdate );
806
- iCalUtilityFunctions::_stepdate( $enddate, $endDatets, array( 'month' => 1 )); // make sure to count whole last month
807
- }
808
- else
809
- iCalUtilityFunctions::_stepdate( $enddate, $endDatets, $step); // make sure to count whole last period
810
- // echo "BYSETPOS endDat++ =".implode('-',$enddate).' step='.var_export($step,TRUE)."<br />\n";//test###
811
- $bysetposWold = (int) date( 'W', ( $wdatets + $wkst ));
812
- $bysetposYold = $wdate['year'];
813
- $bysetposMold = $wdate['month'];
814
- $bysetposDold = $wdate['day'];
815
- }
816
- else
817
- iCalUtilityFunctions::_stepdate( $wdate, $wdatets, $step);
818
- $year_old = null;
819
- $daynames = array( 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA' );
820
- /* MAIN LOOP */
821
- // echo "recur start ".implode('-',$wdate)." end ".implode('-',$enddate)."<br />\n";//test
822
- while( TRUE ) {
823
- if( isset( $endDatets ) && ( $wdatets > $endDatets ))
824
- break;
825
- if( isset( $recur['COUNT'] ) && ( $countcnt >= $recur['COUNT'] ))
826
- break;
827
- if( $year_old != $wdate['year'] ) {
828
- $year_old = $wdate['year'];
829
- $daycnts = array();
830
- $yeardays = $weekno = 0;
831
- $yeardaycnt = array();
832
- for( $m = 1; $m <= 12; $m++ ) { // count up and update up-counters
833
- $daycnts[$m] = array();
834
- $weekdaycnt = array();
835
- foreach( $daynames as $dn )
836
- $yeardaycnt[$dn] = $weekdaycnt[$dn] = 0;
837
- $mcnt = date( 't', mktime( 0, 0, 0, $m, 1, $wdate['year'] ));
838
- for( $d = 1; $d <= $mcnt; $d++ ) {
839
- $daycnts[$m][$d] = array();
840
- if( isset( $recur['BYYEARDAY'] )) {
841
- $yeardays++;
842
- $daycnts[$m][$d]['yearcnt_up'] = $yeardays;
843
- }
844
- if( isset( $recur['BYDAY'] )) {
845
- $day = date( 'w', mktime( 0, 0, 0, $m, $d, $wdate['year'] ));
846
- $day = $daynames[$day];
847
- $daycnts[$m][$d]['DAY'] = $day;
848
- $weekdaycnt[$day]++;
849
- $daycnts[$m][$d]['monthdayno_up'] = $weekdaycnt[$day];
850
- $yeardaycnt[$day]++;
851
- $daycnts[$m][$d]['yeardayno_up'] = $yeardaycnt[$day];
852
- }
853
- if( isset( $recur['BYWEEKNO'] ) || ( $recur['FREQ'] == 'WEEKLY' ))
854
- $daycnts[$m][$d]['weekno_up'] =(int)date('W',mktime(0,0,$wkst,$m,$d,$wdate['year']));
855
- }
856
- }
857
- $daycnt = 0;
858
- $yeardaycnt = array();
859
- if( isset( $recur['BYWEEKNO'] ) || ( $recur['FREQ'] == 'WEEKLY' )) {
860
- $weekno = null;
861
- for( $d=31; $d > 25; $d-- ) { // get last weekno for year
862
- if( !$weekno )
863
- $weekno = $daycnts[12][$d]['weekno_up'];
864
- elseif( $weekno < $daycnts[12][$d]['weekno_up'] ) {
865
- $weekno = $daycnts[12][$d]['weekno_up'];
866
- break;
867
- }
868
- }
869
- }
870
- for( $m = 12; $m > 0; $m-- ) { // count down and update down-counters
871
- $weekdaycnt = array();
872
- foreach( $daynames as $dn )
873
- $yeardaycnt[$dn] = $weekdaycnt[$dn] = 0;
874
- $monthcnt = 0;
875
- $mcnt = date( 't', mktime( 0, 0, 0, $m, 1, $wdate['year'] ));
876
- for( $d = $mcnt; $d > 0; $d-- ) {
877
- if( isset( $recur['BYYEARDAY'] )) {
878
- $daycnt -= 1;
879
- $daycnts[$m][$d]['yearcnt_down'] = $daycnt;
880
- }
881
- if( isset( $recur['BYMONTHDAY'] )) {
882
- $monthcnt -= 1;
883
- $daycnts[$m][$d]['monthcnt_down'] = $monthcnt;
884
- }
885
- if( isset( $recur['BYDAY'] )) {
886
- $day = $daycnts[$m][$d]['DAY'];
887
- $weekdaycnt[$day] -= 1;
888
- $daycnts[$m][$d]['monthdayno_down'] = $weekdaycnt[$day];
889
- $yeardaycnt[$day] -= 1;
890
- $daycnts[$m][$d]['yeardayno_down'] = $yeardaycnt[$day];
891
- }
892
- if( isset( $recur['BYWEEKNO'] ) || ( $recur['FREQ'] == 'WEEKLY' ))
893
- $daycnts[$m][$d]['weekno_down'] = ($daycnts[$m][$d]['weekno_up'] - $weekno - 1);
894
- }
895
- }
896
- }
897
- /* check interval */
898
- if( 1 < $recur['INTERVAL'] ) {
899
- /* create interval index */
900
- $intervalix = iCalUtilityFunctions::_recurIntervalIx( $recur['FREQ'], $wdate, $wkst );
901
- /* check interval */
902
- $currentKey = array_keys( $intervalarr );
903
- $currentKey = end( $currentKey ); // get last index
904
- if( $currentKey != $intervalix )
905
- $intervalarr = array( $intervalix => ( $intervalarr[$currentKey] + 1 ));
906
- if(( $recur['INTERVAL'] != $intervalarr[$intervalix] ) &&
907
- ( 0 != $intervalarr[$intervalix] )) {
908
- /* step up date */
909
- // echo "skip: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br />\n";//test
910
- iCalUtilityFunctions::_stepdate( $wdate, $wdatets, $step);
911
- continue;
912
- }
913
- else // continue within the selected interval
914
- $intervalarr[$intervalix] = 0;
915
- // echo "cont: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br />\n";//test
916
- }
917
- $updateOK = TRUE;
918
- if( $updateOK && isset( $recur['BYMONTH'] ))
919
- $updateOK = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYMONTH']
920
- , $wdate['month']
921
- ,($wdate['month'] - 13));
922
- if( $updateOK && isset( $recur['BYWEEKNO'] ))
923
- $updateOK = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYWEEKNO']
924
- , $daycnts[$wdate['month']][$wdate['day']]['weekno_up']
925
- , $daycnts[$wdate['month']][$wdate['day']]['weekno_down'] );
926
- if( $updateOK && isset( $recur['BYYEARDAY'] ))
927
- $updateOK = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYYEARDAY']
928
- , $daycnts[$wdate['month']][$wdate['day']]['yearcnt_up']
929
- , $daycnts[$wdate['month']][$wdate['day']]['yearcnt_down'] );
930
- if( $updateOK && isset( $recur['BYMONTHDAY'] ))
931
- $updateOK = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYMONTHDAY']
932
- , $wdate['day']
933
- , $daycnts[$wdate['month']][$wdate['day']]['monthcnt_down'] );
934
- // echo "efter BYMONTHDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br />\n";//test###
935
- if( $updateOK && isset( $recur['BYDAY'] )) {
936
- $updateOK = FALSE;
937
- $m = $wdate['month'];
938
- $d = $wdate['day'];
939
- if( isset( $recur['BYDAY']['DAY'] )) { // single day, opt with year/month day order no
940
- $daynoexists = $daynosw = $daynamesw = FALSE;
941
- if( $recur['BYDAY']['DAY'] == $daycnts[$m][$d]['DAY'] )
942
- $daynamesw = TRUE;
943
- if( isset( $recur['BYDAY'][0] )) {
944
- $daynoexists = TRUE;
945
- if(( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'MONTHLY' )) || isset( $recur['BYMONTH'] ))
946
- $daynosw = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYDAY'][0]
947
- , $daycnts[$m][$d]['monthdayno_up']
948
- , $daycnts[$m][$d]['monthdayno_down'] );
949
- elseif( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'YEARLY' ))
950
- $daynosw = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYDAY'][0]
951
- , $daycnts[$m][$d]['yeardayno_up']
952
- , $daycnts[$m][$d]['yeardayno_down'] );
953
- }
954
- if(( $daynoexists && $daynosw && $daynamesw ) ||
955
- ( !$daynoexists && !$daynosw && $daynamesw )) {
956
- $updateOK = TRUE;
957
- }
958
- // echo "daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw<br />\n"; // test ###
959
- }
960
- else {
961
- foreach( $recur['BYDAY'] as $bydayvalue ) {
962
- $daynoexists = $daynosw = $daynamesw = FALSE;
963
- if( isset( $bydayvalue['DAY'] ) &&
964
- ( $bydayvalue['DAY'] == $daycnts[$m][$d]['DAY'] ))
965
- $daynamesw = TRUE;
966
- if( isset( $bydayvalue[0] )) {
967
- $daynoexists = TRUE;
968
- if(( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'MONTHLY' )) ||
969
- isset( $recur['BYMONTH'] ))
970
- $daynosw = iCalUtilityFunctions::_recurBYcntcheck( $bydayvalue['0']
971
- , $daycnts[$m][$d]['monthdayno_up']
972
- , $daycnts[$m][$d]['monthdayno_down'] );
973
- elseif( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'YEARLY' ))
974
- $daynosw = iCalUtilityFunctions::_recurBYcntcheck( $bydayvalue['0']
975
- , $daycnts[$m][$d]['yeardayno_up']
976
- , $daycnts[$m][$d]['yeardayno_down'] );
977
- }
978
- // echo "daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw<br />\n"; // test ###
979
- if(( $daynoexists && $daynosw && $daynamesw ) ||
980
- ( !$daynoexists && !$daynosw && $daynamesw )) {
981
- $updateOK = TRUE;
982
- break;
983
- }
984
- }
985
- }
986
- }
987
- // echo "efter BYDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br />\n"; // test ###
988
- /* check BYSETPOS */
989
- if( $updateOK ) {
990
- if( isset( $recur['BYSETPOS'] ) &&
991
- ( in_array( $recur['FREQ'], array( 'YEARLY', 'MONTHLY', 'WEEKLY', 'DAILY' )))) {
992
- if( isset( $recur['WEEKLY'] )) {
993
- if( $bysetposWold == $daycnts[$wdate['month']][$wdate['day']]['weekno_up'] )
994
- $bysetposw1[] = $wdatets;
995
- else
996
- $bysetposw2[] = $wdatets;
997
- }
998
- else {
999
- if(( isset( $recur['FREQ'] ) && ( 'YEARLY' == $recur['FREQ'] ) &&
1000
- ( $bysetposYold == $wdate['year'] )) ||
1001
- ( isset( $recur['FREQ'] ) && ( 'MONTHLY' == $recur['FREQ'] ) &&
1002
- (( $bysetposYold == $wdate['year'] ) &&
1003
- ( $bysetposMold == $wdate['month'] ))) ||
1004
- ( isset( $recur['FREQ'] ) && ( 'DAILY' == $recur['FREQ'] ) &&
1005
- (( $bysetposYold == $wdate['year'] ) &&
1006
- ( $bysetposMold == $wdate['month']) &&
1007
- ( $bysetposDold == $wdate['day'] )))) {
1008
- // echo "bysetposymd1[]=".implode('-',iCalUtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
1009
- $bysetposymd1[] = $wdatets;
1010
- }
1011
- else {
1012
- // echo "bysetposymd2[]=".implode('-',iCalUtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
1013
- $bysetposymd2[] = $wdatets;
1014
- }
1015
- }
1016
- }
1017
- else {
1018
- /* update result array if BYSETPOS is set */
1019
- $countcnt++;
1020
- if( $startdatets <= $wdatets ) { // only output within period
1021
- $result[$wdatets] = TRUE;
1022
- // echo "recur ".implode('-',iCalUtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
1023
- }
1024
- // echo "recur undate ".implode('-',iCalUtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$wdatets),6))." okdatstart ".implode('-',iCalUtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$startdatets),6))."<br />\n";//test
1025
- $updateOK = FALSE;
1026
- }
1027
- }
1028
- /* step up date */
1029
- iCalUtilityFunctions::_stepdate( $wdate, $wdatets, $step);
1030
- /* check if BYSETPOS is set for updating result array */
1031
- if( $updateOK && isset( $recur['BYSETPOS'] )) {
1032
- $bysetpos = FALSE;
1033
- if( isset( $recur['FREQ'] ) && ( 'YEARLY' == $recur['FREQ'] ) &&
1034
- ( $bysetposYold != $wdate['year'] )) {
1035
- $bysetpos = TRUE;
1036
- $bysetposYold = $wdate['year'];
1037
- }
1038
- elseif( isset( $recur['FREQ'] ) && ( 'MONTHLY' == $recur['FREQ'] &&
1039
- (( $bysetposYold != $wdate['year'] ) || ( $bysetposMold != $wdate['month'] )))) {
1040
- $bysetpos = TRUE;
1041
- $bysetposYold = $wdate['year'];
1042
- $bysetposMold = $wdate['month'];
1043
- }
1044
- elseif( isset( $recur['FREQ'] ) && ( 'WEEKLY' == $recur['FREQ'] )) {
1045
- $weekno = (int) date( 'W', mktime( 0, 0, $wkst, $wdate['month'], $wdate['day'], $wdate['year']));
1046
- if( $bysetposWold != $weekno ) {
1047
- $bysetposWold = $weekno;
1048
- $bysetpos = TRUE;
1049
- }
1050
- }
1051
- elseif( isset( $recur['FREQ'] ) && ( 'DAILY' == $recur['FREQ'] ) &&
1052
- (( $bysetposYold != $wdate['year'] ) ||
1053
- ( $bysetposMold != $wdate['month'] ) ||
1054
- ( $bysetposDold != $wdate['day'] ))) {
1055
- $bysetpos = TRUE;
1056
- $bysetposYold = $wdate['year'];
1057
- $bysetposMold = $wdate['month'];
1058
- $bysetposDold = $wdate['day'];
1059
- }
1060
- if( $bysetpos ) {
1061
- if( isset( $recur['BYWEEKNO'] )) {
1062
- $bysetposarr1 = & $bysetposw1;
1063
- $bysetposarr2 = & $bysetposw2;
1064
- }
1065
- else {
1066
- $bysetposarr1 = & $bysetposymd1;
1067
- $bysetposarr2 = & $bysetposymd2;
1068
- }
1069
- // echo 'test före out startYMD (weekno)='.$wdateStart['year'].':'.$wdateStart['month'].':'.$wdateStart['day']." ($weekStart) "; // test ###
1070
- foreach( $recur['BYSETPOS'] as $ix ) {
1071
- if( 0 > $ix ) // both positive and negative BYSETPOS allowed
1072
- $ix = ( count( $bysetposarr1 ) + $ix + 1);
1073
- $ix--;
1074
- if( isset( $bysetposarr1[$ix] )) {
1075
- if( $startdatets <= $bysetposarr1[$ix] ) { // only output within period
1076
- // $testdate = iCalUtilityFunctions::_timestamp2date( $bysetposarr1[$ix], 6 ); // test ###
1077
- // $testweekno = (int) date( 'W', mktime( 0, 0, $wkst, $testdate['month'], $testdate['day'], $testdate['year'] )); // test ###
1078
- // echo " testYMD (weekno)=".$testdate['year'].':'.$testdate['month'].':'.$testdate['day']." ($testweekno)"; // test ###
1079
- $result[$bysetposarr1[$ix]] = TRUE;
1080
- // echo " recur ".implode('-',iCalUtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$bysetposarr1[$ix]),6)); // test ###
1081
- }
1082
- $countcnt++;
1083
- }
1084
- if( isset( $recur['COUNT'] ) && ( $countcnt >= $recur['COUNT'] ))
1085
- break;
1086
- }
1087
- // echo "<br />\n"; // test ###
1088
- $bysetposarr1 = $bysetposarr2;
1089
- $bysetposarr2 = array();
1090
- }
1091
- }
1092
- }
1093
- }
1094
- public static function _recurBYcntcheck( $BYvalue, $upValue, $downValue ) {
1095
- if( is_array( $BYvalue ) &&
1096
- ( in_array( $upValue, $BYvalue ) || in_array( $downValue, $BYvalue )))
1097
- return TRUE;
1098
- elseif(( $BYvalue == $upValue ) || ( $BYvalue == $downValue ))
1099
- return TRUE;
1100
- else
1101
- return FALSE;
1102
- }
1103
- public static function _recurIntervalIx( $freq, $date, $wkst ) {
1104
- /* create interval index */
1105
- switch( $freq ) {
1106
- case 'YEARLY':
1107
- $intervalix = $date['year'];
1108
- break;
1109
- case 'MONTHLY':
1110
- $intervalix = $date['year'].'-'.$date['month'];
1111
- break;
1112
- case 'WEEKLY':
1113
- $wdatets = iCalUtilityFunctions::_date2timestamp( $date );
1114
- $intervalix = (int) date( 'W', ( $wdatets + $wkst ));
1115
- break;
1116
- case 'DAILY':
1117
- default:
1118
- $intervalix = $date['year'].'-'.$date['month'].'-'.$date['day'];
1119
- break;
1120
- }
1121
- return $intervalix;
1122
- }
1123
- /**
1124
- * convert input format for exrule and rrule to internal format
1125
- *
1126
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1127
- * @since 2.9.10 - 2011-07-07
1128
- * @param array $rexrule
1129
- * @return array
1130
- */
1131
- public static function _setRexrule( $rexrule ) {
1132
- $input = array();
1133
- if( empty( $rexrule ))
1134
- return $input;
1135
- foreach( $rexrule as $rexrulelabel => $rexrulevalue ) {
1136
- $rexrulelabel = strtoupper( $rexrulelabel );
1137
- if( 'UNTIL' != $rexrulelabel )
1138
- $input[$rexrulelabel] = $rexrulevalue;
1139
- else {
1140
- if( iCalUtilityFunctions::_isArrayTimestampDate( $rexrulevalue )) // timestamp date
1141
- $input[$rexrulelabel] = iCalUtilityFunctions::_timestamp2date( $rexrulevalue, 6 );
1142
- elseif( iCalUtilityFunctions::_isArrayDate( $rexrulevalue )) // date-time
1143
- $input[$rexrulelabel] = iCalUtilityFunctions::_date_time_array( $rexrulevalue, 6 );
1144
- elseif( 8 <= strlen( trim( $rexrulevalue ))) // ex. 2006-08-03 10:12:18
1145
- $input[$rexrulelabel] = iCalUtilityFunctions::_date_time_string( $rexrulevalue );
1146
- if(( 3 < count( $input[$rexrulelabel] )) && !isset( $input[$rexrulelabel]['tz'] ))
1147
- $input[$rexrulelabel]['tz'] = 'Z';
1148
- }
1149
- }
1150
- /* set recurrence rule specification in rfc2445 order */
1151
- $input2 = array();
1152
- if( isset( $input['FREQ'] ))
1153
- $input2['FREQ'] = $input['FREQ'];
1154
- if( isset( $input['UNTIL'] ))
1155
- $input2['UNTIL'] = $input['UNTIL'];
1156
- elseif( isset( $input['COUNT'] ))
1157
- $input2['COUNT'] = $input['COUNT'];
1158
- if( isset( $input['INTERVAL'] ))
1159
- $input2['INTERVAL'] = $input['INTERVAL'];
1160
- if( isset( $input['BYSECOND'] ))
1161
- $input2['BYSECOND'] = $input['BYSECOND'];
1162
- if( isset( $input['BYMINUTE'] ))
1163
- $input2['BYMINUTE'] = $input['BYMINUTE'];
1164
- if( isset( $input['BYHOUR'] ))
1165
- $input2['BYHOUR'] = $input['BYHOUR'];
1166
- if( isset( $input['BYDAY'] )) {
1167
- if( !is_array( $input['BYDAY'] )) // ensure upper case.. .
1168
- $input2['BYDAY'] = strtoupper( $input['BYDAY'] );
1169
- else {
1170
- foreach( $input['BYDAY'] as $BYDAYx => $BYDAYv ) {
1171
- if( 'DAY' == strtoupper( $BYDAYx ))
1172
- $input2['BYDAY']['DAY'] = strtoupper( $BYDAYv );
1173
- elseif( !is_array( $BYDAYv )) {
1174
- $input2['BYDAY'][$BYDAYx] = $BYDAYv;
1175
- }
1176
- else {
1177
- foreach( $BYDAYv as $BYDAYx2 => $BYDAYv2 ) {
1178
- if( 'DAY' == strtoupper( $BYDAYx2 ))
1179
- $input2['BYDAY'][$BYDAYx]['DAY'] = strtoupper( $BYDAYv2 );
1180
- else
1181
- $input2['BYDAY'][$BYDAYx][$BYDAYx2] = $BYDAYv2;
1182
- }
1183
- }
1184
- }
1185
- }
1186
- }
1187
- if( isset( $input['BYMONTHDAY'] ))
1188
- $input2['BYMONTHDAY'] = $input['BYMONTHDAY'];
1189
- if( isset( $input['BYYEARDAY'] ))
1190
- $input2['BYYEARDAY'] = $input['BYYEARDAY'];
1191
- if( isset( $input['BYWEEKNO'] ))
1192
- $input2['BYWEEKNO'] = $input['BYWEEKNO'];
1193
- if( isset( $input['BYMONTH'] ))
1194
- $input2['BYMONTH'] = $input['BYMONTH'];
1195
- if( isset( $input['BYSETPOS'] ))
1196
- $input2['BYSETPOS'] = $input['BYSETPOS'];
1197
- if( isset( $input['WKST'] ))
1198
- $input2['WKST'] = $input['WKST'];
1199
- return $input2;
1200
- }
1201
- /**
1202
- * convert format for input date to internal date with parameters
1203
- *
1204
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1205
- * @since 2.9.6 - 2011-05-14
1206
- * @param mixed $year
1207
- * @param mixed $month optional
1208
- * @param int $day optional
1209
- * @param int $hour optional
1210
- * @param int $min optional
1211
- * @param int $sec optional
1212
- * @param string $tz optional
1213
- * @param array $params optional
1214
- * @param string $caller optional
1215
- * @param string $objName optional
1216
- * @param string $tzid optional
1217
- * @return array
1218
- */
1219
- public static function _setDate( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE, $caller=null, $objName=null, $tzid=FALSE ) {
1220
- $input = $parno = null;
1221
- $localtime = (( 'dtstart' == $caller ) && in_array( $objName, array( 'vtimezone', 'standard', 'daylight' ))) ? TRUE : FALSE;
1222
- if( iCalUtilityFunctions::_isArrayDate( $year )) {
1223
- if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
1224
- $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
1225
- if( isset( $input['params']['TZID'] )) {
1226
- $input['params']['VALUE'] = 'DATE-TIME';
1227
- unset( $year['tz'] );
1228
- }
1229
- $hitval = (( !empty( $year['tz'] ) || !empty( $year[6] ))) ? 7 : 6;
1230
- $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval );
1231
- $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3, count( $year ), $parno );
1232
- $input['value'] = iCalUtilityFunctions::_date_time_array( $year, $parno );
1233
- }
1234
- elseif( iCalUtilityFunctions::_isArrayTimestampDate( $year )) {
1235
- if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
1236
- $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
1237
- if( isset( $input['params']['TZID'] )) {
1238
- $input['params']['VALUE'] = 'DATE-TIME';
1239
- unset( $year['tz'] );
1240
- }
1241
- $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3 );
1242
- $hitval = ( isset( $year['tz'] )) ? 7 : 6;
1243
- $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno );
1244
- $input['value'] = iCalUtilityFunctions::_timestamp2date( $year, $parno );
1245
- }
1246
- elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18
1247
- if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
1248
- $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
1249
- if( isset( $input['params']['TZID'] )) {
1250
- $input['params']['VALUE'] = 'DATE-TIME';
1251
- $parno = 6;
1252
- }
1253
- $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7, $parno );
1254
- $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3, $parno, $parno );
1255
- $input['value'] = iCalUtilityFunctions::_date_time_string( $year, $parno );
1256
- }
1257
- else {
1258
- if( is_array( $params )) {
1259
- if( $localtime ) unset ( $params['VALUE'], $params['TZID'] );
1260
- $input['params'] = iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' ));
1261
- }
1262
- elseif( is_array( $tz )) {
1263
- $input['params'] = iCalUtilityFunctions::_setParams( $tz, array( 'VALUE' => 'DATE-TIME' ));
1264
- $tz = FALSE;
1265
- }
1266
- elseif( is_array( $hour )) {
1267
- $input['params'] = iCalUtilityFunctions::_setParams( $hour, array( 'VALUE' => 'DATE-TIME' ));
1268
- $hour = $min = $sec = $tz = FALSE;
1269
- }
1270
- if( isset( $input['params']['TZID'] )) {
1271
- $tz = null;
1272
- $input['params']['VALUE'] = 'DATE-TIME';
1273
- }
1274
- $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3 );
1275
- $hitval = ( !empty( $tz )) ? 7 : 6;
1276
- $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno, $parno );
1277
- $input['value'] = array( 'year' => $year, 'month' => $month, 'day' => $day );
1278
- if( 3 != $parno ) {
1279
- $input['value']['hour'] = ( $hour ) ? $hour : '0';
1280
- $input['value']['min'] = ( $min ) ? $min : '0';
1281
- $input['value']['sec'] = ( $sec ) ? $sec : '0';
1282
- if( !empty( $tz ))
1283
- $input['value']['tz'] = $tz;
1284
- }
1285
- }
1286
- if( 3 == $parno ) {
1287
- $input['params']['VALUE'] = 'DATE';
1288
- unset( $input['value']['tz'] );
1289
- unset( $input['params']['TZID'] );
1290
- }
1291
- elseif( isset( $input['params']['TZID'] ))
1292
- unset( $input['value']['tz'] );
1293
- if( $localtime )
1294
- unset( $input['value']['tz'], $input['params']['TZID'] );
1295
- elseif(( !isset( $input['params']['VALUE'] ) || ( $input['params']['VALUE'] != 'DATE' )) && !isset( $input['params']['TZID'] ) && $tzid )
1296
- $input['params']['TZID'] = $tzid;
1297
- if( isset( $input['value']['tz'] ))
1298
- $input['value']['tz'] = (string) $input['value']['tz'];
1299
- if( !empty( $input['value']['tz'] ) && ( 'Z' != $input['value']['tz'] ) &&
1300
- ( !iCalUtilityFunctions::_isOffset( $input['value']['tz'] )))
1301
- $input['params']['TZID'] = $input['value']['tz'];
1302
- return $input;
1303
- }
1304
- /**
1305
- * convert format for input date (UTC) to internal date with parameters
1306
- *
1307
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1308
- * @since 2.4.17 - 2008-10-31
1309
- * @param mixed $year
1310
- * @param mixed $month optional
1311
- * @param int $day optional
1312
- * @param int $hour optional
1313
- * @param int $min optional
1314
- * @param int $sec optional
1315
- * @param array $params optional
1316
- * @return array
1317
- */
1318
- public static function _setDate2( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
1319
- $input = null;
1320
- if( iCalUtilityFunctions::_isArrayDate( $year )) {
1321
- $input['value'] = iCalUtilityFunctions::_date_time_array( $year, 7 );
1322
- $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
1323
- }
1324
- elseif( iCalUtilityFunctions::_isArrayTimestampDate( $year )) {
1325
- $input['value'] = iCalUtilityFunctions::_timestamp2date( $year, 7 );
1326
- $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
1327
- }
1328
- elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18
1329
- $input['value'] = iCalUtilityFunctions::_date_time_string( $year, 7 );
1330
- $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
1331
- }
1332
- else {
1333
- $input['value'] = array( 'year' => $year
1334
- , 'month' => $month
1335
- , 'day' => $day
1336
- , 'hour' => $hour
1337
- , 'min' => $min
1338
- , 'sec' => $sec );
1339
- $input['params'] = iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' ));
1340
- }
1341
- $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7 ); // remove default
1342
- if( !isset( $input['value']['hour'] ))
1343
- $input['value']['hour'] = 0;
1344
- if( !isset( $input['value']['min'] ))
1345
- $input['value']['min'] = 0;
1346
- if( !isset( $input['value']['sec'] ))
1347
- $input['value']['sec'] = 0;
1348
- if( !isset( $input['value']['tz'] ) || !iCalUtilityFunctions::_isOffset( $input['value']['tz'] ))
1349
- $input['value']['tz'] = 'Z';
1350
- return $input;
1351
- }
1352
- /**
1353
- * check index and set (an indexed) content in multiple value array
1354
- *
1355
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1356
- * @since 2.6.12 - 2011-01-03
1357
- * @param array $valArr
1358
- * @param mixed $value
1359
- * @param array $params
1360
- * @param array $defaults
1361
- * @param int $index
1362
- * @return void
1363
- */
1364
- public static function _setMval( & $valArr, $value, $params=FALSE, $defaults=FALSE, $index=FALSE ) {
1365
- if( !is_array( $valArr )) $valArr = array();
1366
- if( $index )
1367
- $index = $index - 1;
1368
- elseif( 0 < count( $valArr )) {
1369
- $keys = array_keys( $valArr );
1370
- $index = end( $keys ) + 1;
1371
- }
1372
- else
1373
- $index = 0;
1374
- $valArr[$index] = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params, $defaults ));
1375
- ksort( $valArr );
1376
- }
1377
- /**
1378
- * set input (formatted) parameters- component property attributes
1379
- *
1380
- * default parameters can be set, if missing
1381
- *
1382
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1383
- * @since 1.x.x - 2007-05-01
1384
- * @param array $params
1385
- * @param array $defaults
1386
- * @return array
1387
- */
1388
- public static function _setParams( $params, $defaults=FALSE ) {
1389
- if( !is_array( $params))
1390
- $params = array();
1391
- $input = array();
1392
- foreach( $params as $paramKey => $paramValue ) {
1393
- if( is_array( $paramValue )) {
1394
- foreach( $paramValue as $pkey => $pValue ) {
1395
- if(( '"' == substr( $pValue, 0, 1 )) && ( '"' == substr( $pValue, -1 )))
1396
- $paramValue[$pkey] = substr( $pValue, 1, ( strlen( $pValue ) - 2 ));
1397
- }
1398
- }
1399
- elseif(( '"' == substr( $paramValue, 0, 1 )) && ( '"' == substr( $paramValue, -1 )))
1400
- $paramValue = substr( $paramValue, 1, ( strlen( $paramValue ) - 2 ));
1401
- if( 'VALUE' == strtoupper( $paramKey ))
1402
- $input['VALUE'] = strtoupper( $paramValue );
1403
- else
1404
- $input[strtoupper( $paramKey )] = $paramValue;
1405
- }
1406
- if( is_array( $defaults )) {
1407
- foreach( $defaults as $paramKey => $paramValue ) {
1408
- if( !isset( $input[$paramKey] ))
1409
- $input[$paramKey] = $paramValue;
1410
- }
1411
- }
1412
- return (0 < count( $input )) ? $input : null;
1413
- }
1414
- /**
1415
- * step date, return updated date, array and timpstamp
1416
- *
1417
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1418
- * @since 2.4.16 - 2008-10-18
1419
- * @param array $date, date to step
1420
- * @param int $timestamp
1421
- * @param array $step, default array( 'day' => 1 )
1422
- * @return void
1423
- */
1424
- public static function _stepdate( &$date, &$timestamp, $step=array( 'day' => 1 )) {
1425
- foreach( $step as $stepix => $stepvalue )
1426
- $date[$stepix] += $stepvalue;
1427
- $timestamp = iCalUtilityFunctions::_date2timestamp( $date );
1428
- $date = iCalUtilityFunctions::_timestamp2date( $timestamp, 6 );
1429
- foreach( $date as $k => $v ) {
1430
- if( ctype_digit( $v ))
1431
- $date[$k] = (int) $v;
1432
- }
1433
- }
1434
- /**
1435
- * convert timestamp to date array
1436
- *
1437
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1438
- * @since 2.4.16 - 2008-11-01
1439
- * @param mixed $timestamp
1440
- * @param int $parno
1441
- * @return array
1442
- */
1443
- public static function _timestamp2date( $timestamp, $parno=6 ) {
1444
- if( is_array( $timestamp )) {
1445
- if(( 7 == $parno ) && !empty( $timestamp['tz'] ))
1446
- $tz = $timestamp['tz'];
1447
- $timestamp = $timestamp['timestamp'];
1448
- }
1449
- $output = array( 'year' => date( 'Y', $timestamp )
1450
- , 'month' => date( 'm', $timestamp )
1451
- , 'day' => date( 'd', $timestamp ));
1452
- if( 3 != $parno ) {
1453
- $output['hour'] = date( 'H', $timestamp );
1454
- $output['min'] = date( 'i', $timestamp );
1455
- $output['sec'] = date( 's', $timestamp );
1456
- if( isset( $tz ))
1457
- $output['tz'] = $tz;
1458
- }
1459
- return $output;
1460
- }
1461
- /**
1462
- * convert timestamp to duration in array format
1463
- *
1464
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1465
- * @since 2.6.23 - 2010-10-23
1466
- * @param int $timestamp
1467
- * @return array, duration format
1468
- */
1469
- function _timestamp2duration( $timestamp ) {
1470
- $dur = array();
1471
- $dur['week'] = (int) floor( $timestamp / ( 7 * 24 * 60 * 60 ));
1472
- $timestamp = $timestamp % ( 7 * 24 * 60 * 60 );
1473
- $dur['day'] = (int) floor( $timestamp / ( 24 * 60 * 60 ));
1474
- $timestamp = $timestamp % ( 24 * 60 * 60 );
1475
- $dur['hour'] = (int) floor( $timestamp / ( 60 * 60 ));
1476
- $timestamp = $timestamp % ( 60 * 60 );
1477
- $dur['min'] = (int) floor( $timestamp / ( 60 ));
1478
- $dur['sec'] = (int) $timestamp % ( 60 );
1479
- return $dur;
1480
- }
1481
- /**
1482
- * convert (numeric) local time offset to seconds correcting localtime to GMT
1483
- *
1484
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1485
- * @since 2.4.16 - 2008-10-19
1486
- * @param string $offset
1487
- * @return integer
1488
- */
1489
- public static function _tz2offset( $tz ) {
1490
- $tz = trim( (string) $tz );
1491
- $offset = 0;
1492
- if((( 5 != strlen( $tz )) && ( 7 != strlen( $tz ))) ||
1493
- (( '+' != substr( $tz, 0, 1 )) && ( '-' != substr( $tz, 0, 1 ))) ||
1494
- (( '0000' >= substr( $tz, 1, 4 )) && ( '9999' < substr( $tz, 1, 4 ))) ||
1495
- (( 7 == strlen( $tz )) && ( '00' > substr( $tz, 5, 2 )) && ( '99' < substr( $tz, 5, 2 ))))
1496
- return $offset;
1497
- $hours2sec = (int) substr( $tz, 1, 2 ) * 3600;
1498
- $min2sec = (int) substr( $tz, 3, 2 ) * 60;
1499
- $sec = ( 7 == strlen( $tz )) ? (int) substr( $tz, -2 ) : '00';
1500
- $offset = $hours2sec + $min2sec + $sec;
1501
- $offset = ('-' == substr( $tz, 0, 1 )) ? $offset : -1 * $offset;
1502
- return $offset;
1503
- }
1504
- }
1505
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/iCalcreator-2.10/iCalcreator.class.php DELETED
@@ -1,6890 +0,0 @@
1
- <?php
2
- /*********************************************************************************/
3
- /**
4
- * iCalcreator class v2.10
5
- * copyright (c) 2007-2011 Kjell-Inge Gustafsson kigkonsult
6
- * www.kigkonsult.se/iCalcreator/index.php
7
- * ical@kigkonsult.se
8
- *
9
- * Description:
10
- * This file is a PHP implementation of RFC 2445.
11
- *
12
- * This library is free software; you can redistribute it and/or
13
- * modify it under the terms of the GNU Lesser General Public
14
- * License as published by the Free Software Foundation; either
15
- * version 2.1 of the License, or (at your option) any later version.
16
- *
17
- * This library is distributed in the hope that it will be useful,
18
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20
- * Lesser General Public License for more details.
21
- *
22
- * You should have received a copy of the GNU Lesser General Public
23
- * License along with this library; if not, write to the Free Software
24
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
- */
26
- /*********************************************************************************/
27
- /*********************************************************************************/
28
- /* A little setup */
29
- /*********************************************************************************/
30
- /* your local language code */
31
- // define( 'ICAL_LANG', 'sv' );
32
- // alt. autosetting
33
- /*
34
- $langstr = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
35
- $pos = strpos( $langstr, ';' );
36
- if ($pos !== false) {
37
- $langstr = substr( $langstr, 0, $pos );
38
- $pos = strpos( $langstr, ',' );
39
- if ($pos !== false) {
40
- $pos = strpos( $langstr, ',' );
41
- $langstr = substr( $langstr, 0, $pos );
42
- }
43
- define( 'ICAL_LANG', $langstr );
44
- }
45
- */
46
- /*********************************************************************************/
47
- /* since 2.6.22 - 2010-09-25, do NOT remove!! */
48
- require_once ( 'iCalUtilityFunctions.class.php' );
49
- /*********************************************************************************/
50
- /* version, do NOT remove!! */
51
- define( 'ICALCREATOR_VERSION', 'iCalcreator 2.10' );
52
- /*********************************************************************************/
53
- /*********************************************************************************/
54
- /**
55
- * vcalendar class
56
- *
57
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
58
- * @since 2.9.6 - 2011-05-14
59
- */
60
- class vcalendar {
61
- // calendar property variables
62
- var $calscale;
63
- var $method;
64
- var $prodid;
65
- var $version;
66
- var $xprop;
67
- // container for calendar components
68
- var $components;
69
- // component config variables
70
- var $allowEmpty;
71
- var $unique_id;
72
- var $language;
73
- var $directory;
74
- var $filename;
75
- var $url;
76
- var $delimiter;
77
- var $nl;
78
- var $format;
79
- var $dtzid;
80
- // component internal variables
81
- var $attributeDelimiter;
82
- var $valueInit;
83
- // component xCal declaration container
84
- var $xcaldecl;
85
- /**
86
- * constructor for calendar object
87
- *
88
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
89
- * @since 2.9.6 - 2011-05-14
90
- * @param array $config
91
- * @return void
92
- */
93
- function vcalendar ( $config = array()) {
94
- $this->_makeVersion();
95
- $this->calscale = null;
96
- $this->method = null;
97
- $this->_makeUnique_id();
98
- $this->prodid = null;
99
- $this->xprop = array();
100
- $this->language = null;
101
- $this->directory = null;
102
- $this->filename = null;
103
- $this->url = null;
104
- $this->dtzid = null;
105
- /**
106
- * language = <Text identifying a language, as defined in [RFC 1766]>
107
- */
108
- if( defined( 'ICAL_LANG' ) && !isset( $config['language'] ))
109
- $config['language'] = ICAL_LANG;
110
- if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE;
111
- if( !isset( $config['nl'] )) $config['nl'] = "\r\n";
112
- if( !isset( $config['format'] )) $config['format'] = 'iCal';
113
- if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR;
114
- $this->setConfig( $config );
115
-
116
- $this->xcaldecl = array();
117
- $this->components = array();
118
- }
119
- /*********************************************************************************/
120
- /**
121
- * Property Name: CALSCALE
122
- */
123
- /**
124
- * creates formatted output for calendar property calscale
125
- *
126
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
127
- * @since 2.4.8 - 2008-10-21
128
- * @return string
129
- */
130
- function createCalscale() {
131
- if( empty( $this->calscale )) return FALSE;
132
- switch( $this->format ) {
133
- case 'xcal':
134
- return ' calscale="'.$this->calscale.'"'.$this->nl;
135
- break;
136
- default:
137
- return 'CALSCALE:'.$this->calscale.$this->nl;
138
- break;
139
- }
140
- }
141
- /**
142
- * set calendar property calscale
143
- *
144
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
145
- * @since 2.4.8 - 2008-10-21
146
- * @param string $value
147
- * @return void
148
- */
149
- function setCalscale( $value ) {
150
- if( empty( $value )) return FALSE;
151
- $this->calscale = $value;
152
- }
153
- /*********************************************************************************/
154
- /**
155
- * Property Name: METHOD
156
- */
157
- /**
158
- * creates formatted output for calendar property method
159
- *
160
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
161
- * @since 0.9.7 - 2006-11-20
162
- * @return string
163
- */
164
- function createMethod() {
165
- if( empty( $this->method )) return FALSE;
166
- switch( $this->format ) {
167
- case 'xcal':
168
- return ' method="'.$this->method.'"'.$this->nl;
169
- break;
170
- default:
171
- return 'METHOD:'.$this->method.$this->nl;
172
- break;
173
- }
174
- }
175
- /**
176
- * set calendar property method
177
- *
178
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
179
- * @since 2.4.8 - 2008-20-23
180
- * @param string $value
181
- * @return bool
182
- */
183
- function setMethod( $value ) {
184
- if( empty( $value )) return FALSE;
185
- $this->method = $value;
186
- return TRUE;
187
- }
188
- /*********************************************************************************/
189
- /**
190
- * Property Name: PRODID
191
- *
192
- * The identifier is RECOMMENDED to be the identical syntax to the
193
- * [RFC 822] addr-spec. A good method to assure uniqueness is to put the
194
- * domain name or a domain literal IP address of the host on which.. .
195
- */
196
- /**
197
- * creates formatted output for calendar property prodid
198
- *
199
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
200
- * @since 0.9.7 - 2006-11-20
201
- * @return string
202
- */
203
- function createProdid() {
204
- if( !isset( $this->prodid ))
205
- $this->_makeProdid();
206
- switch( $this->format ) {
207
- case 'xcal':
208
- return ' prodid="'.$this->prodid.'"'.$this->nl;
209
- break;
210
- default:
211
- return 'PRODID:'.$this->prodid.$this->nl;
212
- break;
213
- }
214
- }
215
- /**
216
- * make default value for calendar prodid
217
- *
218
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
219
- * @since 2.6.8 - 2009-12-30
220
- * @return void
221
- */
222
- function _makeProdid() {
223
- $this->prodid = '-//'.$this->unique_id.'//NONSGML kigkonsult.se '.ICALCREATOR_VERSION.'//'.strtoupper( $this->language );
224
- }
225
- /**
226
- * Conformance: The property MUST be specified once in an iCalendar object.
227
- * Description: The vendor of the implementation SHOULD assure that this
228
- * is a globally unique identifier; using some technique such as an FPI
229
- * value, as defined in [ISO 9070].
230
- */
231
- /**
232
- * make default unique_id for calendar prodid
233
- *
234
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
235
- * @since 0.3.0 - 2006-08-10
236
- * @return void
237
- */
238
- function _makeUnique_id() {
239
- $this->unique_id = ( isset( $_SERVER['SERVER_NAME'] )) ? gethostbyname( $_SERVER['SERVER_NAME'] ) : 'localhost';
240
- }
241
- /*********************************************************************************/
242
- /**
243
- * Property Name: VERSION
244
- *
245
- * Description: A value of "2.0" corresponds to this memo.
246
- */
247
- /**
248
- * creates formatted output for calendar property version
249
-
250
- *
251
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
252
- * @since 0.9.7 - 2006-11-20
253
- * @return string
254
- */
255
- function createVersion() {
256
- if( empty( $this->version ))
257
- $this->_makeVersion();
258
- switch( $this->format ) {
259
- case 'xcal':
260
- return ' version="'.$this->version.'"'.$this->nl;
261
- break;
262
- default:
263
- return 'VERSION:'.$this->version.$this->nl;
264
- break;
265
- }
266
- }
267
- /**
268
- * set default calendar version
269
- *
270
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
271
- * @since 0.3.0 - 2006-08-10
272
- * @return void
273
- */
274
- function _makeVersion() {
275
- $this->version = '2.0';
276
- }
277
- /**
278
- * set calendar version
279
- *
280
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
281
- * @since 2.4.8 - 2008-10-23
282
- * @param string $value
283
- * @return void
284
- */
285
- function setVersion( $value ) {
286
- if( empty( $value )) return FALSE;
287
- $this->version = $value;
288
- return TRUE;
289
- }
290
- /*********************************************************************************/
291
- /**
292
- * Property Name: x-prop
293
- */
294
- /**
295
- * creates formatted output for calendar property x-prop, iCal format only
296
- *
297
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
298
- * @since 2.9.3 - 2011-05-14
299
- * @return string
300
- */
301
- function createXprop() {
302
- if( 'xcal' == $this->format )
303
- return false;
304
- if( empty( $this->xprop ) || !is_array( $this->xprop )) return FALSE;
305
- $output = null;
306
- $toolbox = new calendarComponent();
307
- $toolbox->setConfig( $this->getConfig());
308
- foreach( $this->xprop as $label => $xpropPart ) {
309
- if( !isset($xpropPart['value']) || ( empty( $xpropPart['value'] ) && !is_numeric( $xpropPart['value'] ))) {
310
- $output .= $toolbox->_createElement( $label );
311
- continue;
312
- }
313
- $attributes = $toolbox->_createParams( $xpropPart['params'], array( 'LANGUAGE' ));
314
- if( is_array( $xpropPart['value'] )) {
315
- foreach( $xpropPart['value'] as $pix => $theXpart )
316
- $xpropPart['value'][$pix] = $toolbox->_strrep( $theXpart );
317
- $xpropPart['value'] = implode( ',', $xpropPart['value'] );
318
- }
319
- else
320
- $xpropPart['value'] = $toolbox->_strrep( $xpropPart['value'] );
321
- $output .= $toolbox->_createElement( $label, $attributes, $xpropPart['value'] );
322
- }
323
- return $output;
324
- }
325
- /**
326
- * set calendar property x-prop
327
- *
328
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
329
- * @since 2.9.3 - 2011-05-14
330
- * @param string $label
331
- * @param string $value
332
- * @param array $params optional
333
- * @return bool
334
- */
335
- function setXprop( $label, $value, $params=FALSE ) {
336
- if( empty( $label )) return FALSE;
337
- if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
338
- $xprop = array( 'value' => $value );
339
- $xprop['params'] = iCalUtilityFunctions::_setParams( $params );
340
- if( !is_array( $this->xprop )) $this->xprop = array();
341
- $this->xprop[strtoupper( $label )] = $xprop;
342
- return TRUE;
343
- }
344
- /*********************************************************************************/
345
- /**
346
- * delete calendar property value
347
- *
348
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
349
- * @since 2.8.8 - 2011-03-15
350
- * @param mixed $propName, bool FALSE => X-property
351
- * @param int $propix, optional, if specific property is wanted in case of multiply occurences
352
- * @return bool, if successfull delete
353
- */
354
- function deleteProperty( $propName=FALSE, $propix=FALSE ) {
355
- $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
356
- if( !$propix )
357
- $propix = ( isset( $this->propdelix[$propName] ) && ( 'X-PROP' != $propName )) ? $this->propdelix[$propName] + 2 : 1;
358
- $this->propdelix[$propName] = --$propix;
359
- $return = FALSE;
360
- switch( $propName ) {
361
- case 'CALSCALE':
362
- if( isset( $this->calscale )) {
363
- $this->calscale = null;
364
- $return = TRUE;
365
- }
366
- break;
367
- case 'METHOD':
368
- if( isset( $this->method )) {
369
- $this->method = null;
370
- $return = TRUE;
371
- }
372
- break;
373
- default:
374
- $reduced = array();
375
- if( $propName != 'X-PROP' ) {
376
- if( !isset( $this->xprop[$propName] )) { unset( $this->propdelix[$propName] ); return FALSE; }
377
- foreach( $this->xprop as $k => $a ) {
378
- if(( $k != $propName ) && !empty( $a ))
379
- $reduced[$k] = $a;
380
- }
381
- }
382
- else {
383
- if( count( $this->xprop ) <= $propix ) return FALSE;
384
- $xpropno = 0;
385
- foreach( $this->xprop as $xpropkey => $xpropvalue ) {
386
- if( $propix != $xpropno )
387
- $reduced[$xpropkey] = $xpropvalue;
388
- $xpropno++;
389
- }
390
- }
391
- $this->xprop = $reduced;
392
- if( empty( $this->xprop )) {
393
- unset( $this->propdelix[$propName] );
394
- return FALSE;
395
- }
396
- return TRUE;
397
- }
398
- return $return;
399
- }
400
- /**
401
- * get calendar property value/params
402
- *
403
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
404
- * @since 2.8.8 - 2011-04-16
405
- * @param string $propName, optional
406
- * @param int $propix, optional, if specific property is wanted in case of multiply occurences
407
- * @param bool $inclParam=FALSE
408
- * @return mixed
409
- */
410
- function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE ) {
411
- $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
412
- if( 'X-PROP' == $propName ) {
413
- if( !$propix )
414
- $propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1;
415
- $this->propix[$propName] = --$propix;
416
- }
417
- switch( $propName ) {
418
- case 'ATTENDEE':
419
- case 'CATEGORIES':
420
- case 'DTSTART':
421
- case 'LOCATION':
422
- case 'ORGANIZER':
423
- case 'PRIORITY':
424
- case 'RESOURCES':
425
- case 'STATUS':
426
- case 'SUMMARY':
427
- case 'RECURRENCE-ID-UID':
428
- case 'R-UID':
429
- case 'UID':
430
- $output = array();
431
- foreach ( $this->components as $cix => $component) {
432
- if( !in_array( $component->objName, array('vevent', 'vtodo', 'vjournal', 'vfreebusy' )))
433
- continue;
434
- if(( 'ATTENDEE' == $propName ) || ( 'CATEGORIES' == $propName ) || ( 'RESOURCES' == $propName )) {
435
- $component->_getProperties( $propName, $output );
436
- continue;
437
- }
438
- elseif(( 3 < strlen( $propName )) && ( 'UID' == substr( $propName, -3 ))) {
439
- if( FALSE !== ( $content = $component->getProperty( 'RECURRENCE-ID' )))
440
- $content = $component->getProperty( 'UID' );
441
- }
442
- elseif( FALSE === ( $content = $component->getProperty( $propName )))
443
- continue;
444
- if( FALSE === $content )
445
- continue;
446
- elseif( is_array( $content )) {
447
- if( isset( $content['year'] )) {
448
- $key = sprintf( '%04d%02d%02d', $content['year'], $content['month'], $content['day'] );
449
- if( !isset( $output[$key] ))
450
- $output[$key] = 1;
451
- else
452
- $output[$key] += 1;
453
- }
454
- else {
455
- foreach( $content as $partValue => $partCount ) {
456
- if( !isset( $output[$partValue] ))
457
- $output[$partValue] = $partCount;
458
- else
459
- $output[$partValue] += $partCount;
460
- }
461
- }
462
- } // end elseif( is_array( $content )) {
463
- elseif( !isset( $output[$content] ))
464
- $output[$content] = 1;
465
- else
466
- $output[$content] += 1;
467
- } // end foreach ( $this->components as $cix => $component)
468
- if( !empty( $output ))
469
- ksort( $output );
470
- return $output;
471
- break;
472
-
473
- case 'CALSCALE':
474
- return ( !empty( $this->calscale )) ? $this->calscale : FALSE;
475
- break;
476
- case 'METHOD':
477
- return ( !empty( $this->method )) ? $this->method : FALSE;
478
- break;
479
- case 'PRODID':
480
- if( empty( $this->prodid ))
481
- $this->_makeProdid();
482
- return $this->prodid;
483
- break;
484
- case 'VERSION':
485
- return ( !empty( $this->version )) ? $this->version : FALSE;
486
- break;
487
- default:
488
- if( $propName != 'X-PROP' ) {
489
- if( !isset( $this->xprop[$propName] )) return FALSE;
490
- return ( $inclParam ) ? array( $propName, $this->xprop[$propName] )
491
- : array( $propName, $this->xprop[$propName]['value'] );
492
- }
493
- else {
494
- if( empty( $this->xprop )) return FALSE;
495
- $xpropno = 0;
496
- foreach( $this->xprop as $xpropkey => $xpropvalue ) {
497
- if( $propix == $xpropno )
498
- return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] )
499
- : array( $xpropkey, $this->xprop[$xpropkey]['value'] );
500
- else
501
- $xpropno++;
502
- }
503
- unset( $this->propix[$propName] );
504
- return FALSE; // not found ??
505
- }
506
- }
507
- return FALSE;
508
- }
509
- /**
510
- * general vcalendar property setting
511
- *
512
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
513
- * @since 2.2.13 - 2007-11-04
514
- * @param mixed $args variable number of function arguments,
515
- * first argument is ALWAYS component name,
516
- * second ALWAYS component value!
517
- * @return bool
518
- */
519
- function setProperty () {
520
- $numargs = func_num_args();
521
- if( 1 > $numargs )
522
- return FALSE;
523
- $arglist = func_get_args();
524
- $arglist[0] = strtoupper( $arglist[0] );
525
- switch( $arglist[0] ) {
526
- case 'CALSCALE':
527
- return $this->setCalscale( $arglist[1] );
528
- case 'METHOD':
529
- return $this->setMethod( $arglist[1] );
530
- case 'VERSION':
531
- return $this->setVersion( $arglist[1] );
532
- default:
533
- if( !isset( $arglist[1] )) $arglist[1] = null;
534
- if( !isset( $arglist[2] )) $arglist[2] = null;
535
- return $this->setXprop( $arglist[0], $arglist[1], $arglist[2] );
536
- }
537
- return FALSE;
538
- }
539
- /*********************************************************************************/
540
- /**
541
- * get vcalendar config values or * calendar components
542
- *
543
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
544
- * @since 2.9.6 - 2011-05-14
545
- * @param mixed $config
546
- * @return value
547
- */
548
- function getConfig( $config = FALSE ) {
549
- if( !$config ) {
550
- $return = array();
551
- $return['ALLOWEMPTY'] = $this->getConfig( 'ALLOWEMPTY' );
552
- $return['DELIMITER'] = $this->getConfig( 'DELIMITER' );
553
- $return['DIRECTORY'] = $this->getConfig( 'DIRECTORY' );
554
- $return['FILENAME'] = $this->getConfig( 'FILENAME' );
555
- $return['DIRFILE'] = $this->getConfig( 'DIRFILE' );
556
- $return['FILESIZE'] = $this->getConfig( 'FILESIZE' );
557
- $return['FORMAT'] = $this->getConfig( 'FORMAT' );
558
- if( FALSE !== ( $lang = $this->getConfig( 'LANGUAGE' )))
559
- $return['LANGUAGE'] = $lang;
560
- $return['NEWLINECHAR'] = $this->getConfig( 'NEWLINECHAR' );
561
- $return['UNIQUE_ID'] = $this->getConfig( 'UNIQUE_ID' );
562
- if( FALSE !== ( $url = $this->getConfig( 'URL' )))
563
- $return['URL'] = $url;
564
- $return['TZID'] = $this->getConfig( 'TZID' );
565
- return $return;
566
- }
567
- switch( strtoupper( $config )) {
568
- case 'ALLOWEMPTY':
569
- return $this->allowEmpty;
570
- break;
571
- case 'COMPSINFO':
572
- unset( $this->compix );
573
- $info = array();
574
- foreach( $this->components as $cix => $component ) {
575
- if( empty( $component )) continue;
576
- $info[$cix]['ordno'] = $cix + 1;
577
- $info[$cix]['type'] = $component->objName;
578
- $info[$cix]['uid'] = $component->getProperty( 'uid' );
579
- $info[$cix]['props'] = $component->getConfig( 'propinfo' );
580
- $info[$cix]['sub'] = $component->getConfig( 'compsinfo' );
581
- }
582
- return $info;
583
- break;
584
- case 'DELIMITER':
585
- return $this->delimiter;
586
- break;
587
- case 'DIRECTORY':
588
- if( empty( $this->directory ))
589
- $this->directory = '.';
590
- return $this->directory;
591
- break;
592
- case 'DIRFILE':
593
- return $this->getConfig( 'directory' ).$this->getConfig( 'delimiter' ).$this->getConfig( 'filename' );
594
- break;
595
- case 'FILEINFO':
596
- return array( $this->getConfig( 'directory' )
597
- , $this->getConfig( 'filename' )
598
- , $this->getConfig( 'filesize' ));
599
- break;
600
- case 'FILENAME':
601
- if( empty( $this->filename )) {
602
- if( 'xcal' == $this->format )
603
- $this->filename = date( 'YmdHis' ).'.xml'; // recommended xcs.. .
604
- else
605
- $this->filename = date( 'YmdHis' ).'.ics';
606
- }
607
- return $this->filename;
608
- break;
609
- case 'FILESIZE':
610
- $size = 0;
611
- if( empty( $this->url )) {
612
- $dirfile = $this->getConfig( 'dirfile' );
613
- if( !is_file( $dirfile ) || ( FALSE === ( $size = filesize( $dirfile ))))
614
- $size = 0;
615
- clearstatcache();
616
- }
617
- return $size;
618
- break;
619
- case 'FORMAT':
620
- return ( $this->format == 'xcal' ) ? 'xCal' : 'iCal';
621
- break;
622
- case 'LANGUAGE':
623
- /* get language for calendar component as defined in [RFC 1766] */
624
- return $this->language;
625
- break;
626
- case 'NL':
627
- case 'NEWLINECHAR':
628
- return $this->nl;
629
- break;
630
- case 'TZID':
631
- return $this->dtzid;
632
- break;
633
- case 'UNIQUE_ID':
634
- return $this->unique_id;
635
- break;
636
- case 'URL':
637
- if( !empty( $this->url ))
638
- return $this->url;
639
- else
640
- return FALSE;
641
- break;
642
- }
643
- }
644
- /**
645
- * general vcalendar config setting
646
- *
647
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
648
- * @since 2.9.6 - 2011-05-14
649
- * @param mixed $config
650
- * @param string $value
651
- * @return void
652
- */
653
- function setConfig( $config, $value = FALSE) {
654
- if( is_array( $config )) {
655
- foreach( $config as $cKey => $cValue ) {
656
- if( FALSE === $this->setConfig( $cKey, $cValue ))
657
- return FALSE;
658
- }
659
- return TRUE;
660
- }
661
- $res = FALSE;
662
- switch( strtoupper( $config )) {
663
- case 'ALLOWEMPTY':
664
- $this->allowEmpty = $value;
665
- $subcfg = array( 'ALLOWEMPTY' => $value );
666
- $res = TRUE;
667
- break;
668
- case 'DELIMITER':
669
- $this->delimiter = $value;
670
- return TRUE;
671
- break;
672
- case 'DIRECTORY':
673
- $value = trim( $value );
674
- $del = $this->getConfig('delimiter');
675
- if( $del == substr( $value, ( 0 - strlen( $del ))))
676
- $value = substr( $value, 0, ( strlen( $value ) - strlen( $del )));
677
- if( is_dir( $value )) {
678
- /* local directory */
679
- clearstatcache();
680
- $this->directory = $value;
681
- $this->url = null;
682
- return TRUE;
683
- }
684
- else
685
- return FALSE;
686
- break;
687
- case 'FILENAME':
688
- $value = trim( $value );
689
- if( !empty( $this->url )) {
690
- /* remote directory+file -> URL */
691
- $this->filename = $value;
692
- return TRUE;
693
- }
694
- $dirfile = $this->getConfig( 'directory' ).$this->getConfig( 'delimiter' ).$value;
695
- if( file_exists( $dirfile )) {
696
- /* local file exists */
697
- if( is_readable( $dirfile ) || is_writable( $dirfile )) {
698
- clearstatcache();
699
- $this->filename = $value;
700
- return TRUE;
701
- }
702
- else
703
- return FALSE;
704
- }
705
- elseif( is_readable($this->getConfig( 'directory' ) ) || is_writable( $this->getConfig( 'directory' ) )) {
706
- /* read- or writable directory */
707
- $this->filename = $value;
708
- return TRUE;
709
- }
710
- else
711
- return FALSE;
712
- break;
713
- case 'FORMAT':
714
- $value = trim( strtolower( $value ));
715
- if( 'xcal' == $value ) {
716
- $this->format = 'xcal';
717
- $this->attributeDelimiter = $this->nl;
718
- $this->valueInit = null;
719
- }
720
- else {
721
- $this->format = null;
722
- $this->attributeDelimiter = ';';
723
- $this->valueInit = ':';
724
- }
725
- $subcfg = array( 'FORMAT' => $value );
726
- $res = TRUE;
727
- break;
728
- case 'LANGUAGE':
729
- // set language for calendar component as defined in [RFC 1766]
730
- $value = trim( $value );
731
- $this->language = $value;
732
- $subcfg = array( 'LANGUAGE' => $value );
733
- $res = TRUE;
734
- break;
735
- case 'NL':
736
- case 'NEWLINECHAR':
737
- $this->nl = $value;
738
- $subcfg = array( 'NL' => $value );
739
- $res = TRUE;
740
- break;
741
- case 'TZID':
742
- $this->dtzid = $value;
743
- $subcfg = array( 'TZID' => $value );
744
- $res = TRUE;
745
- break;
746
- case 'UNIQUE_ID':
747
- $value = trim( $value );
748
- $this->unique_id = $value;
749
- $subcfg = array( 'UNIQUE_ID' => $value );
750
- $res = TRUE;
751
- break;
752
- case 'URL':
753
- /* remote file - URL */
754
- $value = trim( $value );
755
- $value = str_replace( 'HTTP://', 'http://', $value );
756
- $value = str_replace( 'WEBCAL://', 'http://', $value );
757
- $value = str_replace( 'webcal://', 'http://', $value );
758
- $this->url = $value;
759
- $this->directory = null;
760
- $parts = pathinfo( $value );
761
- return $this->setConfig( 'filename', $parts['basename'] );
762
- break;
763
- default: // any unvalid config key.. .
764
- return TRUE;
765
- }
766
- if( !$res ) return FALSE;
767
- if( isset( $subcfg ) && !empty( $this->components )) {
768
- foreach( $subcfg as $cfgkey => $cfgvalue ) {
769
- foreach( $this->components as $cix => $component ) {
770
- $res = $component->setConfig( $cfgkey, $cfgvalue, TRUE );
771
- if( !$res )
772
- break 2;
773
- $this->components[$cix] = $component->copy(); // PHP4 compliant
774
- }
775
- }
776
- }
777
- return $res;
778
- }
779
- /*********************************************************************************/
780
- /**
781
- * add calendar component to container
782
- *
783
- * alias to setComponent
784
- *
785
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
786
- * @since 1.x.x - 2007-04-24
787
- * @param object $component calendar component
788
- * @return void
789
- */
790
- function addComponent( $component ) {
791
- $this->setComponent( $component );
792
- }
793
- /**
794
- * delete calendar component from container
795
- *
796
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
797
- * @since 2.8.8 - 2011-03-15
798
- * @param mixed $arg1 ordno / component type / component uid
799
- * @param mixed $arg2 optional, ordno if arg1 = component type
800
- * @return void
801
- */
802
- function deleteComponent( $arg1, $arg2=FALSE ) {
803
- $argType = $index = null;
804
- if ( ctype_digit( (string) $arg1 )) {
805
- $argType = 'INDEX';
806
- $index = (int) $arg1 - 1;
807
- }
808
- elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
809
- $argType = strtolower( $arg1 );
810
- $index = ( !empty( $arg2 ) && ctype_digit( (string) $arg2 )) ? (( int ) $arg2 - 1 ) : 0;
811
- }
812
- $cix1dC = 0;
813
- foreach ( $this->components as $cix => $component) {
814
- if( empty( $component )) continue;
815
- if(( 'INDEX' == $argType ) && ( $index == $cix )) {
816
- unset( $this->components[$cix] );
817
- return TRUE;
818
- }
819
- elseif( $argType == $component->objName ) {
820
- if( $index == $cix1dC ) {
821
- unset( $this->components[$cix] );
822
- return TRUE;
823
- }
824
- $cix1dC++;
825
- }
826
- elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) {
827
- unset( $this->components[$cix] );
828
- return TRUE;
829
- }
830
- }
831
- return FALSE;
832
- }
833
- /**
834
- * get calendar component from container
835
- *
836
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
837
- * @since 2.9.1 - 2011-04-16
838
- * @param mixed $arg1 optional, ordno/component type/ component uid
839
- * @param mixed $arg2 optional, ordno if arg1 = component type
840
- * @return object
841
- */
842
- function getComponent( $arg1=FALSE, $arg2=FALSE ) {
843
- $index = $argType = null;
844
- if ( !$arg1 ) { // first or next in component chain
845
- $argType = 'INDEX';
846
- $index = $this->compix['INDEX'] = ( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1;
847
- }
848
- elseif ( ctype_digit( (string) $arg1 )) { // specific component in chain
849
- $argType = 'INDEX';
850
- $index = (int) $arg1;
851
- unset( $this->compix );
852
- }
853
- elseif( is_array( $arg1 )) { // array( *[propertyName => propertyValue] )
854
- $arg2 = implode( '-', array_keys( $arg1 ));
855
- $index = $this->compix[$arg2] = ( isset( $this->compix[$arg2] )) ? $this->compix[$arg2] + 1 : 1;
856
- $dateProps = array( 'DTSTART', 'DTEND', 'DUE', 'CREATED', 'COMPLETED', 'DTSTAMP', 'LAST-MODIFIED', 'RECURRENCE-ID' );
857
- $otherProps = array( 'ATTENDEE', 'CATEGORIES', 'LOCATION', 'ORGANIZER', 'PRIORITY', 'RESOURCES', 'STATUS', 'SUMMARY', 'UID' );
858
- }
859
- elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) { // object class name
860
- unset( $this->compix['INDEX'] );
861
- $argType = strtolower( $arg1 );
862
- if( !$arg2 )
863
- $index = $this->compix[$argType] = ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1;
864
- elseif( isset( $arg2 ) && ctype_digit( (string) $arg2 ))
865
- $index = (int) $arg2;
866
- }
867
- elseif(( strlen( $arg1 ) > strlen( 'vfreebusy' )) && ( FALSE !== strpos( $arg1, '@' ))) { // UID as 1st argument
868
- if( !$arg2 )
869
- $index = $this->compix[$arg1] = ( isset( $this->compix[$arg1] )) ? $this->compix[$arg1] + 1 : 1;
870
- elseif( isset( $arg2 ) && ctype_digit( (string) $arg2 ))
871
- $index = (int) $arg2;
872
- }
873
- if( isset( $index ))
874
- $index -= 1;
875
- $ckeys = array_keys( $this->components );
876
- if( !empty( $index) && ( $index > end( $ckeys )))
877
- return FALSE;
878
- $cix1gC = 0;
879
- foreach ( $this->components as $cix => $component) {
880
- if( empty( $component )) continue;
881
- if(( 'INDEX' == $argType ) && ( $index == $cix ))
882
- return $component->copy();
883
- elseif( $argType == $component->objName ) {
884
- if( $index == $cix1gC )
885
- return $component->copy();
886
- $cix1gC++;
887
- }
888
- elseif( is_array( $arg1 )) { // array( *[propertyName => propertyValue] )
889
- $hit = FALSE;
890
- foreach( $arg1 as $pName => $pValue ) {
891
- $pName = strtoupper( $pName );
892
- if( !in_array( $pName, $dateProps ) && !in_array( $pName, $otherProps ))
893
- continue;
894
- if(( 'ATTENDEE' == $pName ) || ( 'CATEGORIES' == $pName ) || ( 'RESOURCES' == $pName )) { // multiple ocurrence may occur
895
- $propValues = array();
896
- $component->_getProperties( $pName, $propValues );
897
- $propValues = array_keys( $propValues );
898
- $hit = ( in_array( $pValue, $propValues )) ? TRUE : FALSE;
899
- continue;
900
- } // end if(( 'CATEGORIES' == $propName ) || ( 'RESOURCES' == $propName )) { // multiple ocurrence may occur
901
- if( FALSE === ( $value = $component->getProperty( $pName ))) { // single ocurrency
902
- $hit = FALSE; // missing property
903
- continue;
904
- }
905
- if( 'SUMMARY' == $pName ) { // exists within (any case)
906
- $hit = ( FALSE !== stripos( $d, $pValue )) ? TRUE : FALSE;
907
- continue;
908
- }
909
- if( in_array( strtoupper( $pName ), $dateProps )) {
910
- $valuedate = sprintf( '%04d%02d%02d', $value['year'], $value['month'], $value['day'] );
911
- if( 8 < strlen( $pValue )) {
912
- if( isset( $value['hour'] )) {
913
- if( 'T' == substr( $pValue, 8, 1 ))
914
- $pValue = str_replace( 'T', '', $pValue );
915
- $valuedate .= sprintf( '%02d%02d%02d', $value['hour'], $value['min'], $value['sec'] );
916
- }
917
- else
918
- $pValue = substr( $pValue, 0, 8 );
919
- }
920
- $hit = ( $pValue == $valuedate ) ? TRUE : FALSE;
921
- continue;
922
- }
923
- elseif( !is_array( $value ))
924
- $value = array( $value );
925
- foreach( $value as $part ) {
926
- $part = ( FALSE !== strpos( $part, ',' )) ? explode( ',', $part ) : array( $part );
927
- foreach( $part as $subPart ) {
928
- if( $pValue == $subPart ) {
929
- $hit = TRUE;
930
- continue 2;
931
- }
932
- }
933
- }
934
- $hit = FALSE; // no hit in property
935
- } // end foreach( $arg1 as $pName => $pValue )
936
- if( $hit ) {
937
- if( $index == $cix1gC )
938
- return $component->copy();
939
- $cix1gC++;
940
- }
941
- } // end elseif( is_array( $arg1 )) { // array( *[propertyName => propertyValue] )
942
- elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) { // UID
943
- if( $index == $cix1gC )
944
- return $component->copy();
945
- $cix1gC++;
946
- }
947
- } // end foreach ( $this->components.. .
948
- /* not found.. . */
949
- unset( $this->compix );
950
- return FALSE;
951
- }
952
- /**
953
- * create new calendar component, already included within calendar
954
- *
955
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
956
- * @since 2.6.33 - 2011-01-03
957
- * @param string $compType component type
958
- * @return object (reference)
959
- */
960
- function & newComponent( $compType ) {
961
- $config = $this->getConfig();
962
- $keys = array_keys( $this->components );
963
- $ix = end( $keys) + 1;
964
- switch( strtoupper( $compType )) {
965
- case 'EVENT':
966
- case 'VEVENT':
967
- $this->components[$ix] = new vevent( $config );
968
- break;
969
- case 'TODO':
970
- case 'VTODO':
971
- $this->components[$ix] = new vtodo( $config );
972
- break;
973
- case 'JOURNAL':
974
- case 'VJOURNAL':
975
- $this->components[$ix] = new vjournal( $config );
976
- break;
977
- case 'FREEBUSY':
978
- case 'VFREEBUSY':
979
- $this->components[$ix] = new vfreebusy( $config );
980
- break;
981
- case 'TIMEZONE':
982
- case 'VTIMEZONE':
983
- array_unshift( $this->components, new vtimezone( $config ));
984
- $ix = 0;
985
- break;
986
- default:
987
- return FALSE;
988
- }
989
- return $this->components[$ix];
990
- }
991
- /**
992
- * select components from calendar on date or selectOption basis
993
- *
994
- * Ensure DTSTART is set for every component.
995
- * No date controls occurs.
996
- *
997
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
998
- * @since 2.9.7 - 2011-06-04
999
- * @param mixed $startY optional, start Year, default current Year ALT. array selecOptions
1000
- * @param int $startM optional, start Month, default current Month
1001
- * @param int $startD optional, start Day, default current Day
1002
- * @param int $endY optional, end Year, default $startY
1003
- * @param int $endY optional, end Month, default $startM
1004
- * @param int $endY optional, end Day, default $startD
1005
- * @param mixed $cType optional, calendar component type(-s), default FALSE=all else string/array type(-s)
1006
- * @param bool $flat optional, FALSE (default) => output : array[Year][Month][Day][]
1007
- * TRUE => output : array[] (ignores split)
1008
- * @param bool $any optional, TRUE (default) - select component that take place within period
1009
- * FALSE - only components that starts within period
1010
- * @param bool $split optional, TRUE (default) - one component copy every day it take place during the
1011
- * period (implies flat=FALSE)
1012
- * FALSE - one occurance of component only in output array
1013
- * @return array or FALSE
1014
- */
1015
- function selectComponents( $startY=FALSE, $startM=FALSE, $startD=FALSE, $endY=FALSE, $endM=FALSE, $endD=FALSE, $cType=FALSE, $flat=FALSE, $any=TRUE, $split=TRUE ) {
1016
- /* check if empty calendar */
1017
- if( 0 >= count( $this->components )) return FALSE;
1018
- if( is_array( $startY ))
1019
- return $this->selectComponents2( $startY );
1020
- /* check default dates */
1021
- if( !$startY ) $startY = date( 'Y' );
1022
- if( !$startM ) $startM = date( 'm' );
1023
- if( !$startD ) $startD = date( 'd' );
1024
- $startDate = mktime( 0, 0, 0, $startM, $startD, $startY );
1025
- if( !$endY ) $endY = $startY;
1026
- if( !$endM ) $endM = $startM;
1027
- if( !$endD ) $endD = $startD;
1028
- $endDate = mktime( 23, 59, 59, $endM, $endD, $endY );
1029
- //echo 'selectComp arg='.date( 'Y-m-d H:i:s', $startDate).' -- '.date( 'Y-m-d H:i:s', $endDate)."<br />\n"; $tcnt = 0;// test ###
1030
- /* check component types */
1031
- $validTypes = array('vevent', 'vtodo', 'vjournal', 'vfreebusy' );
1032
- if( is_array( $cType )) {
1033
- foreach( $cType as $cix => $theType ) {
1034
- $cType[$cix] = $theType = strtolower( $theType );
1035
- if( !in_array( $theType, $validTypes ))
1036
- $cType[$cix] = 'vevent';
1037
- }
1038
- $cType = array_unique( $cType );
1039
- }
1040
- elseif( !empty( $cType )) {
1041
- $cType = strtolower( $cType );
1042
- if( !in_array( $cType, $validTypes ))
1043
- $cType = array( 'vevent' );
1044
- else
1045
- $cType = array( $cType );
1046
- }
1047
- else
1048
- $cType = $validTypes;
1049
- if( 0 >= count( $cType ))
1050
- $cType = $validTypes;
1051
- if(( TRUE === $flat ) && ( TRUE === $split )) // invalid combination
1052
- $split = FALSE;
1053
- /* iterate components */
1054
- $result = array();
1055
- foreach ( $this->components as $cix => $component ) {
1056
- if( empty( $component )) continue;
1057
- unset( $start );
1058
- /* deselect unvalid type components */
1059
- if( !in_array( $component->objName, $cType )) continue;
1060
- $start = $component->getProperty( 'dtstart' );
1061
- /* select due when dtstart is missing */
1062
- if( empty( $start ) && ( $component->objName == 'vtodo' ) && ( FALSE === ( $start = $component->getProperty( 'due' ))))
1063
- continue;
1064
- $dtendExist = $dueExist = $durationExist = $endAllDayEvent = FALSE;
1065
- unset( $end, $startWdate, $endWdate, $rdurWsecs, $rdur, $exdatelist, $workstart, $workend, $endDateFormat ); // clean up
1066
- $startWdate = iCalUtilityFunctions::_date2timestamp( $start );
1067
- $startDateFormat = ( isset( $start['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d';
1068
- /* get end date from dtend/due/duration properties */
1069
- $end = $component->getProperty( 'dtend' );
1070
- if( !empty( $end )) {
1071
- $dtendExist = TRUE;
1072
- $endDateFormat = ( isset( $end['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d';
1073
- }
1074
- if( empty( $end ) && ( $component->objName == 'vtodo' )) {
1075
- $end = $component->getProperty( 'due' );
1076
- if( !empty( $end )) {
1077
- $dueExist = TRUE;
1078
- $endDateFormat = ( isset( $end['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d';
1079
- }
1080
- }
1081
- if( !empty( $end ) && !isset( $end['hour'] )) {
1082
- /* a DTEND without time part regards an event that ends the day before,
1083
- for an all-day event DTSTART=20071201 DTEND=20071202 (taking place 20071201!!! */
1084
- $endAllDayEvent = TRUE;
1085
- $endWdate = mktime( 23, 59, 59, $end['month'], ($end['day'] - 1), $end['year'] );
1086
- $end['year'] = date( 'Y', $endWdate );
1087
- $end['month'] = date( 'm', $endWdate );
1088
- $end['day'] = date( 'd', $endWdate );
1089
- $end['hour'] = 23;
1090
- $end['min'] = $end['sec'] = 59;
1091
- }
1092
- if( empty( $end )) {
1093
- $end = $component->getProperty( 'duration', FALSE, FALSE, TRUE );// in dtend (array) format
1094
- if( !empty( $end ))
1095
- $durationExist = TRUE;
1096
- $endDateFormat = ( isset( $start['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d';
1097
- // if( !empty($end)) echo 'selectComp 4 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
1098
- }
1099
- if( empty( $end )) { // assume one day duration if missing end date
1100
- $end = array( 'year' => $start['year'], 'month' => $start['month'], 'day' => $start['day'], 'hour' => 23, 'min' => 59, 'sec' => 59 );
1101
- }
1102
- // if( isset($end)) echo 'selectComp 5 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
1103
- $endWdate = iCalUtilityFunctions::_date2timestamp( $end );
1104
- if( $endWdate < $startWdate ) { // MUST be after start date!!
1105
- $end = array( 'year' => $start['year'], 'month' => $start['month'], 'day' => $start['day'], 'hour' => 23, 'min' => 59, 'sec' => 59 );
1106
- $endWdate = iCalUtilityFunctions::_date2timestamp( $end );
1107
- }
1108
- $rdurWsecs = $endWdate - $startWdate; // compute component duration in seconds
1109
- /* make a list of optional exclude dates for component occurence from exrule and exdate */
1110
- $exdatelist = array();
1111
- $workstart = iCalUtilityFunctions::_timestamp2date(( $startDate - $rdurWsecs ), 6);
1112
- $workend = iCalUtilityFunctions::_timestamp2date(( $endDate + $rdurWsecs ), 6);
1113
- while( FALSE !== ( $exrule = $component->getProperty( 'exrule' ))) // check exrule
1114
- iCalUtilityFunctions::_recur2date( $exdatelist, $exrule, $start, $workstart, $workend );
1115
- while( FALSE !== ( $exdate = $component->getProperty( 'exdate' ))) { // check exdate
1116
- foreach( $exdate as $theExdate ) {
1117
- $exWdate = iCalUtilityFunctions::_date2timestamp( $theExdate );
1118
- $exWdate = mktime( 0, 0, 0, date( 'm', $exWdate ), date( 'd', $exWdate ), date( 'Y', $exWdate ) ); // on a day-basis !!!
1119
- if((( $startDate - $rdurWsecs ) <= $exWdate ) && ( $endDate >= $exWdate ))
1120
- $exdatelist[$exWdate] = TRUE;
1121
- }
1122
- }
1123
- /* if 'any' components, check repeating components, removing all excluding dates */
1124
- if( TRUE === $any ) {
1125
- /* make a list of optional repeating dates for component occurence, rrule, rdate */
1126
- $recurlist = array();
1127
- while( FALSE !== ( $rrule = $component->getProperty( 'rrule' ))) // check rrule
1128
- iCalUtilityFunctions::_recur2date( $recurlist, $rrule, $start, $workstart, $workend );
1129
- foreach( $recurlist as $recurkey => $recurvalue ) // key=match date as timestamp
1130
- $recurlist[$recurkey] = $rdurWsecs; // add duration in seconds
1131
- while( FALSE !== ( $rdate = $component->getProperty( 'rdate' ))) { // check rdate
1132
- foreach( $rdate as $theRdate ) {
1133
- if( is_array( $theRdate ) && ( 2 == count( $theRdate )) && // all days within PERIOD
1134
- array_key_exists( '0', $theRdate ) && array_key_exists( '1', $theRdate )) {
1135
- $rstart = iCalUtilityFunctions::_date2timestamp( $theRdate[0] );
1136
- if(( $rstart < ( $startDate - $rdurWsecs )) || ( $rstart > $endDate ))
1137
- continue;
1138
- if( isset( $theRdate[1]['year'] )) // date-date period
1139
- $rend = iCalUtilityFunctions::_date2timestamp( $theRdate[1] );
1140
- else { // date-duration period
1141
- $rend = iCalUtilityFunctions::_duration2date( $theRdate[0], $theRdate[1] );
1142
- $rend = iCalUtilityFunctions::_date2timestamp( $rend );
1143
- }
1144
- while( $rstart < $rend ) {
1145
- $recurlist[$rstart] = $rdurWsecs; // set start date for recurrence instance + rdate duration in seconds
1146
- $rstart = mktime( date( 'H', $rstart ), date( 'i', $rstart ), date( 's', $rstart ), date( 'm', $rstart ), date( 'd', $rstart ) + 1, date( 'Y', $rstart ) ); // step one day
1147
- }
1148
- } // PERIOD end
1149
- else { // single date
1150
- $theRdate = iCalUtilityFunctions::_date2timestamp( $theRdate );
1151
- if((( $startDate - $rdurWsecs ) <= $theRdate ) && ( $endDate >= $theRdate ))
1152
- $recurlist[$theRdate] = $rdurWsecs; // set start date for recurrence instance + event duration in seconds
1153
- }
1154
- }
1155
- }
1156
- if( 0 < count( $recurlist )) {
1157
- ksort( $recurlist );
1158
- $xRecurrence = 1;
1159
- foreach( $recurlist as $recurkey => $durvalue ) {
1160
- // echo "recurKey=".date( 'Y-m-d H:i:s', $recurkey ).' dur='.iCalUtilityFunctions::offsetSec2His( $durvalue )."<br />\n"; // test ###;
1161
- if((( $startDate - $rdurWsecs ) > $recurkey ) || ( $endDate < $recurkey )) // not within period
1162
- continue;
1163
- $checkDate = mktime( 0, 0, 0, date( 'm', $recurkey ), date( 'd', $recurkey ), date( 'Y', $recurkey ) ); // on a day-basis !!!
1164
- if( isset( $exdatelist[$checkDate] )) // check excluded dates
1165
- continue;
1166
- if( $startWdate >= $recurkey ) // exclude component start date
1167
- continue;
1168
- $component2 = $component->copy();
1169
- $rstart = $recurkey;
1170
- $rend = $recurkey + $durvalue;
1171
- /* add repeating components within valid dates to output array, only start date set */
1172
- if( $flat ) {
1173
- $datestring = date( $startDateFormat, $recurkey );
1174
- if( isset( $start['tz'] ))
1175
- $datestring .= ' '.$start['tz'];
1176
- // echo "X-CURRENT-DTSTART 0 =$datestring tcnt =".++$tcnt."<br />";$component2->setProperty( 'X-CNT', $tcnt ); // test ###
1177
- $component2->setProperty( 'X-CURRENT-DTSTART', $datestring );
1178
- if( $dtendExist || $dueExist || $durationExist ) {
1179
- $datestring = date( $endDateFormat, $recurkey + $durvalue ); // fixa korrekt sluttid
1180
- if( isset( $end['tz'] ))
1181
- $datestring .= ' '.$end['tz'];
1182
- $propName = ( !$dueExist ) ? 'X-CURRENT-DTEND' : 'X-CURRENT-DUE';
1183
- $component2->setProperty( $propName, $datestring );
1184
- } // end if( $dtendExist || $dueExist || $durationExist )
1185
- $component2->setProperty( 'X-RECURRENCE', ++$xRecurrence );
1186
- $result[$component2->getProperty( 'UID' )] = $component2->copy(); // copy to output
1187
- }
1188
- /* add repeating components within valid dates to output array, one each day */
1189
- elseif( $split ) {
1190
- if( $rend > $endDate )
1191
- $rend = $endDate;
1192
- $startYMD = date( 'Ymd', $rstart );
1193
- $endYMD = date( 'Ymd', $rend );
1194
- // echo "splitStart=".date( 'Y-m-d H:i:s', $rstart ).' end='.date( 'Y-m-d H:i:s', $rend )."<br />\n"; // test ###;
1195
- while( $rstart <= $rend ) { // iterate.. .
1196
- $checkDate = mktime( 0, 0, 0, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!!
1197
- if( isset( $exdatelist[$checkDate] )) // exclude any recurrence START date, found in exdatelist
1198
- break;
1199
- // echo "checking date after startdate=".date( 'Y-m-d H:i:s', $rstart ).' mot '.date( 'Y-m-d H:i:s', $startDate )."<br />"; // test ###;
1200
- if( $rstart >= $startDate ) { // date after dtstart
1201
- if( date( 'Ymd', $rstart ) > $startYMD ) // date after dtstart
1202
- $datestring = date( $startDateFormat, $checkDate );
1203
- else
1204
- $datestring = date( $startDateFormat, $rstart );
1205
- if( isset( $start['tz'] ))
1206
- $datestring .= ' '.$start['tz'];
1207
- //echo "X-CURRENT-DTSTART 1 = $datestring xRecurrence=$xRecurrence tcnt =".++$tcnt."<br />";$component2->setProperty( 'X-CNT', $tcnt ); // test ###
1208
- $component2->setProperty( 'X-CURRENT-DTSTART', $datestring );
1209
- if( $dtendExist || $dueExist || $durationExist ) {
1210
- if( date( 'Ymd', $rstart ) < $endYMD ) // not the last day
1211
- $tend = mktime( 23, 59, 59, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ));
1212
- else
1213
- $tend = mktime( date( 'H', $endWdate ), date( 'i', $endWdate ), date( 's', $endWdate ), date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!!
1214
- $datestring = date( $endDateFormat, $tend );
1215
- if( isset( $end['tz'] ))
1216
- $datestring .= ' '.$end['tz'];
1217
- $propName = ( !$dueExist ) ? 'X-CURRENT-DTEND' : 'X-CURRENT-DUE';
1218
- $component2->setProperty( $propName, $datestring );
1219
- } // end if( $dtendExist || $dueExist || $durationExist )
1220
- $component2->setProperty( 'X-RECURRENCE', $xRecurrence );
1221
- $wd = getdate( $rstart );
1222
- $result[$wd['year']][$wd['mon']][$wd['mday']][$component2->getProperty( 'UID' )] = $component2->copy(); // copy to output
1223
- } // end if( $checkDate > $startYMD ) { // date after dtstart
1224
- $rstart = mktime( date( 'H', $rstart ), date( 'i', $rstart ), date( 's', $rstart ), date( 'm', $rstart ), date( 'd', $rstart ) + 1, date( 'Y', $rstart ) ); // step one day
1225
- } // end while( $rstart <= $rend )
1226
- $xRecurrence += 1;
1227
- } // end elseif( $split )
1228
- elseif( $rstart >= $startDate ) { // date within period //* flat=FALSE && split=FALSE *//
1229
- $checkDate = mktime( 0, 0, 0, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!!
1230
- if( !isset( $exdatelist[$checkDate] )) { // exclude any recurrence START date, found in exdatelist
1231
- $xRecurrence += 1;
1232
- $datestring = date( $startDateFormat, $rstart );
1233
- if( isset( $start['tz'] ))
1234
- $datestring .= ' '.$start['tz'];
1235
- //echo "X-CURRENT-DTSTART 2 = $datestring xRecurrence=$xRecurrence tcnt =".++$tcnt."<br />";$component2->setProperty( 'X-CNT', $tcnt ); // test ###
1236
- $component2->setProperty( 'X-CURRENT-DTSTART', $datestring );
1237
- if( $dtendExist || $dueExist || $durationExist ) {
1238
- $rstart += $rdurWsecs;
1239
- if( date( 'Ymd', $rstart ) < date( 'Ymd', $endWdate ))
1240
- $tend = mktime( 23, 59, 59, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ));
1241
- else
1242
- $tend = mktime( date( 'H', $endWdate ), date( 'i', $endWdate ), date( 's', $endWdate ), date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!!
1243
- $datestring = date( $endDateFormat, $tend );
1244
- if( isset( $end['tz'] ))
1245
- $datestring .= ' '.$end['tz'];
1246
- $propName = ( !$dueExist ) ? 'X-CURRENT-DTEND' : 'X-CURRENT-DUE';
1247
- $component2->setProperty( $propName, $datestring );
1248
- } // end if( $dtendExist || $dueExist || $durationExist )
1249
- $component2->setProperty( 'X-RECURRENCE', $xRecurrence );
1250
- $wd = getdate( $rstart );
1251
- $result[$wd['year']][$wd['mon']][$wd['mday']][$component2->getProperty( 'UID' )] = $component2->copy(); // copy to output
1252
- } // end if( !isset( $exdatelist[$checkDate] ))
1253
- } // end elseif( $rstart >= $startDate )
1254
- } // end foreach( $recurlist as $recurkey => $durvalue )
1255
- } // end if( 0 < count( $recurlist ))
1256
- /* deselect components with startdate/enddate not within period */
1257
- if(( $endWdate < $startDate ) || ( $startWdate > $endDate ))
1258
- continue;
1259
- } // end if( TRUE === $any )
1260
- /* deselect components with startdate not within period */
1261
- elseif(( $startWdate < $startDate ) || ( $startWdate > $endDate ))
1262
- continue;
1263
- /* add the selected component (WITHIN valid dates) to output array */
1264
- if( $flat )
1265
- $result[$component->getProperty( 'UID' )] = $component->copy(); // copy to output;
1266
- elseif( $split ) { // split the original component
1267
- if( $endWdate > $endDate )
1268
- $endWdate = $endDate; // use period end date
1269
- $rstart = $startWdate;
1270
- if( $rstart < $startDate )
1271
- $rstart = $startDate; // use period start date
1272
- $checkDate = mktime( 0, 0, 0, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!!
1273
- if( !isset( $exdatelist[$checkDate] )) { // exclude any recurrence START date, found in exdatelist
1274
- foreach( array( 'X-CURRENT-DTSTART','X-CURRENT-DTEND','X-CURRENT-DUE','X-RECURRENCE' ) as $propName )
1275
- $component->deleteProperty( $propName ); // remove any x-props, if set
1276
- while( $rstart <= $endWdate ) { // iterate
1277
- if( $rstart > $startWdate ) { // if NOT startdate, set X-properties
1278
- $datestring = date( $startDateFormat, mktime( 0, 0, 0, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart )));
1279
- if( isset( $start['tz'] ))
1280
- $datestring .= ' '.$start['tz'];
1281
- // echo "X-CURRENT-DTSTART 3 = $datestring xRecurrence=$xRecurrence tcnt =".++$tcnt."<br />";$component->setProperty( 'X-CNT', $tcnt ); // test ###
1282
- $component->setProperty( 'X-CURRENT-DTSTART', $datestring );
1283
- if( $dtendExist || $dueExist || $durationExist ) {
1284
- if( date( 'Ymd', $rstart ) < date( 'Ymd', $endWdate ))
1285
- $tend = mktime( 0, 0, 0, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ));
1286
- else
1287
- $tend = mktime( date( 'H', $endWdate ), date( 'i', $endWdate ), date( 's', $endWdate ), date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!!
1288
- $datestring = date( $endDateFormat, $tend );
1289
- if( isset( $end['tz'] ))
1290
- $datestring .= ' '.$end['tz'];
1291
- $propName = ( !$dueExist ) ? 'X-CURRENT-DTEND' : 'X-CURRENT-DUE';
1292
- $component->setProperty( $propName, $datestring );
1293
- } // end if( $dtendExist || $dueExist || $durationExist )
1294
- } // end if( $rstart > $startWdate )
1295
- $wd = getdate( $rstart );
1296
- $result[$wd['year']][$wd['mon']][$wd['mday']][$component->getProperty( 'UID' )] = $component->copy(); // copy to output
1297
- $rstart = mktime( date( 'H', $rstart ), date( 'i', $rstart ), date( 's', $rstart ), date( 'm', $rstart ), date( 'd', $rstart ) + 1, date( 'Y', $rstart ) ); // step one day
1298
- } // end while( $rstart <= $endWdate )
1299
- } // end if( !isset( $exdatelist[$checkDate] ))
1300
- } // end if( $split ) - else use component date
1301
- elseif( $startWdate >= $startDate ) { // within period
1302
- $checkDate = mktime( 0, 0, 0, date( 'm', $startWdate ), date( 'd', $startWdate ), date( 'Y', $startWdate ) ); // on a day-basis !!!
1303
- if( !isset( $exdatelist[$checkDate] )) { // exclude any recurrence START date, found in exdatelist
1304
- foreach( array( 'X-CURRENT-DTSTART','X-CURRENT-DTEND','X-CURRENT-DUE','X-RECURRENCE' ) as $propName )
1305
- $component->deleteProperty( $propName ); // remove any x-props, if set
1306
- $wd = getdate( $startWdate );
1307
- $result[$wd['year']][$wd['mon']][$wd['mday']][$component->getProperty( 'UID' )] = $component->copy(); // copy to output
1308
- }
1309
- }
1310
- } // end foreach ( $this->components as $cix => $component )
1311
- if( 0 >= count( $result )) return FALSE;
1312
- elseif( !$flat ) {
1313
- foreach( $result as $y => $yeararr ) {
1314
- foreach( $yeararr as $m => $montharr ) {
1315
- foreach( $montharr as $d => $dayarr )
1316
- $result[$y][$m][$d] = array_values( $dayarr ); // skip tricky UID-index
1317
- ksort( $result[$y][$m] );
1318
- }
1319
- ksort( $result[$y] );
1320
- }
1321
- ksort( $result );
1322
- } // end elseif( !$flat )
1323
- return $result;
1324
- }
1325
- /**
1326
- * select components from calendar on based on Categories, Location, Resources and/or Summary
1327
- *
1328
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1329
- * @since 2.8.8 - 2011-05-03
1330
- * @param array $selectOptions, (string) key => (mixed) value, (key=propertyName)
1331
- * @return array
1332
- */
1333
- function selectComponents2( $selectOptions ) {
1334
- $output = array();
1335
- $allowedProperties = array( 'ATTENDEE', 'CATEGORIES', 'LOCATION', 'ORGANIZER', 'RESOURCES', 'PRIORITY', 'STATUS', 'SUMMARY', 'UID' );
1336
- foreach( $this->components as $cix => $component3 ) {
1337
- if( !in_array( $component3->objName, array('vevent', 'vtodo', 'vjournal', 'vfreebusy' )))
1338
- continue;
1339
- $uid = $component3->getProperty( 'UID' );
1340
- foreach( $selectOptions as $propName => $pvalue ) {
1341
- $propName = strtoupper( $propName );
1342
- if( !in_array( $propName, $allowedProperties ))
1343
- continue;
1344
- if( !is_array( $pvalue ))
1345
- $pvalue = array( $pvalue );
1346
- if(( 'UID' == $propName ) && in_array( $uid, $pvalue )) {
1347
- $output[] = $component3->copy();
1348
- continue;
1349
- }
1350
- elseif(( 'ATTENDEE' == $propName ) || ( 'CATEGORIES' == $propName ) || ( 'RESOURCES' == $propName )) {
1351
- $propValues = array();
1352
- $component3->_getProperties( $propName, $propValues );
1353
- $propValues = array_keys( $propValues );
1354
- foreach( $pvalue as $theValue ) {
1355
- if( in_array( $theValue, $propValues ) && !isset( $output[$uid] )) {
1356
- $output[$uid] = $component3->copy();
1357
- break;
1358
- }
1359
- }
1360
- continue;
1361
- } // end elseif(( 'ATTENDEE' == $propName ) || ( 'CATEGORIES' == $propName ) || ( 'RESOURCES' == $propName ))
1362
- elseif( FALSE === ( $d = $component3->getProperty( $propName ))) // single ocurrence
1363
- continue;
1364
- if( is_array( $d )) {
1365
- foreach( $d as $part ) {
1366
- if( in_array( $part, $pvalue ) && !isset( $output[$uid] ))
1367
- $output[$uid] = $component3->copy();
1368
- }
1369
- }
1370
- elseif(( 'SUMMARY' == $propName ) && !isset( $output[$uid] )) {
1371
- foreach( $pvalue as $pval ) {
1372
- if( FALSE !== stripos( $d, $pval )) {
1373
- $output[$uid] = $component3->copy();
1374
- break;
1375
- }
1376
- }
1377
- }
1378
- elseif( in_array( $d, $pvalue ) && !isset( $output[$uid] ))
1379
- $output[$uid] = $component3->copy();
1380
- } // end foreach( $selectOptions as $propName => $pvalue ) {
1381
- } // end foreach( $this->components as $cix => $component3 ) {
1382
- if( !empty( $output )) {
1383
- ksort( $output );
1384
- $output = array_values( $output );
1385
- }
1386
- return $output;
1387
- }
1388
- /**
1389
- * add calendar component to container
1390
- *
1391
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1392
- * @since 2.8.8 - 2011-03-15
1393
- * @param object $component calendar component
1394
- * @param mixed $arg1 optional, ordno/component type/ component uid
1395
- * @param mixed $arg2 optional, ordno if arg1 = component type
1396
- * @return void
1397
- */
1398
- function setComponent( $component, $arg1=FALSE, $arg2=FALSE ) {
1399
- $component->setConfig( $this->getConfig(), FALSE, TRUE );
1400
- if( !in_array( $component->objName, array( 'valarm', 'vtimezone' ))) {
1401
- /* make sure dtstamp and uid is set */
1402
- $dummy1 = $component->getProperty( 'dtstamp' );
1403
- $dummy2 = $component->getProperty( 'uid' );
1404
- }
1405
- if( !$arg1 ) { // plain insert, last in chain
1406
- $this->components[] = $component->copy();
1407
- return TRUE;
1408
- }
1409
- $argType = $index = null;
1410
- if ( ctype_digit( (string) $arg1 )) { // index insert/replace
1411
- $argType = 'INDEX';
1412
- $index = (int) $arg1 - 1;
1413
- }
1414
- elseif( in_array( strtolower( $arg1 ), array( 'vevent', 'vtodo', 'vjournal', 'vfreebusy', 'valarm', 'vtimezone' ))) {
1415
- $argType = strtolower( $arg1 );
1416
- $index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0;
1417
- }
1418
- // else if arg1 is set, arg1 must be an UID
1419
- $cix1sC = 0;
1420
- foreach ( $this->components as $cix => $component2) {
1421
- if( empty( $component2 )) continue;
1422
- if(( 'INDEX' == $argType ) && ( $index == $cix )) { // index insert/replace
1423
- $this->components[$cix] = $component->copy();
1424
- return TRUE;
1425
- }
1426
- elseif( $argType == $component2->objName ) { // component Type index insert/replace
1427
- if( $index == $cix1sC ) {
1428
- $this->components[$cix] = $component->copy();
1429
- return TRUE;
1430
- }
1431
- $cix1sC++;
1432
- }
1433
- elseif( !$argType && ( $arg1 == $component2->getProperty( 'uid' ))) { // UID insert/replace
1434
- $this->components[$cix] = $component->copy();
1435
- return TRUE;
1436
- }
1437
- }
1438
- /* arg1=index and not found.. . insert at index .. .*/
1439
- if( 'INDEX' == $argType ) {
1440
- $this->components[$index] = $component->copy();
1441
- ksort( $this->components, SORT_NUMERIC );
1442
- }
1443
- else /* not found.. . insert last in chain anyway .. .*/
1444
- $this->components[] = $component->copy();
1445
- return TRUE;
1446
- }
1447
- /**
1448
- * sort iCal compoments
1449
- *
1450
- * ascending sort on properties (if exist) x-current-dtstart, dtstart,
1451
- * x-current-dtend, dtend, x-current-due, due, duration, created, dtstamp, uid
1452
- * if no arguments, otherwise sorting on argument CATEGORIES, LOCATION, SUMMARY or RESOURCES
1453
- *
1454
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1455
- * @since 2.8.4 - 2011-06-02
1456
- * @param string $sortArg, optional
1457
- * @return void
1458
- *
1459
- */
1460
- function sort( $sortArg=FALSE ) {
1461
- if( is_array( $this->components )) {
1462
- if( $sortArg ) {
1463
- $sortArg = strtoupper( $sortArg );
1464
- if( !in_array( $sortArg, array( 'ATTENDEE', 'CATEGORIES', 'DTSTAMP', 'LOCATION', 'ORGANIZER', 'RESOURCES', 'PRIORITY', 'STATUS', 'SUMMARY' )))
1465
- $sortArg = FALSE;
1466
- }
1467
- /* set sort parameters for each component */
1468
- foreach( $this->components as $cix => & $c ) {
1469
- $c->srtk = array( '0', '0', '0', '0' );
1470
- if( 'vtimezone' == $c->objName ) {
1471
- if( FALSE === ( $c->srtk[0] = $c->getProperty( 'tzid' )))
1472
- $c->srtk[0] = 0;
1473
- continue;
1474
- }
1475
- elseif( $sortArg ) {
1476
- if(( 'ATTENDEE' == $sortArg ) || ( 'CATEGORIES' == $sortArg ) || ( 'RESOURCES' == $sortArg )) {
1477
- $propValues = array();
1478
- $c->_getProperties( $sortArg, $propValues );
1479
- $c->srtk[0] = reset( array_keys( $propValues ));
1480
- }
1481
- elseif( FALSE !== ( $d = $c->getProperty( $sortArg )))
1482
- $c->srtk[0] = $d;
1483
- continue;
1484
- }
1485
- if( FALSE !== ( $d = $c->getProperty( 'X-CURRENT-DTSTART' )))
1486
- $c->srtk[0] = iCalUtilityFunctions::_date_time_string( $d[1] );
1487
- elseif( FALSE === ( $c->srtk[0] = $c->getProperty( 'dtstart' )))
1488
- $c->srtk[1] = 0; // sortkey 0 : dtstart
1489
- if( FALSE !== ( $d = $c->getProperty( 'X-CURRENT-DTEND' )))
1490
- $c->srtk[1] = iCalUtilityFunctions::_date_time_string( $d[1] ); // sortkey 1 : dtend/due(/dtstart+duration)
1491
- elseif( FALSE === ( $c->srtk[1] = $c->getProperty( 'dtend' ))) {
1492
- if( FALSE !== ( $d = $c->getProperty( 'X-CURRENT-DUE' )))
1493
- $c->srtk[1] = iCalUtilityFunctions::_date_time_string( $d[1] );
1494
- elseif( FALSE === ( $c->srtk[1] = $c->getProperty( 'due' )))
1495
- if( FALSE === ( $c->srtk[1] = $c->getProperty( 'duration', FALSE, FALSE, TRUE )))
1496
- $c->srtk[1] = 0;
1497
- }
1498
- if( FALSE === ( $c->srtk[2] = $c->getProperty( 'created' ))) // sortkey 2 : created/dtstamp
1499
- if( FALSE === ( $c->srtk[2] = $c->getProperty( 'dtstamp' )))
1500
- $c->srtk[2] = 0;
1501
- if( FALSE === ( $c->srtk[3] = $c->getProperty( 'uid' ))) // sortkey 3 : uid
1502
- $c->srtk[3] = 0;
1503
- } // end foreach( $this->components as & $c
1504
- /* sort */
1505
- usort( $this->components, array( $this, '_cmpfcn' ));
1506
- }
1507
- }
1508
- function _cmpfcn( $a, $b ) {
1509
- if( empty( $a )) return -1;
1510
- if( empty( $b )) return 1;
1511
- if( 'vtimezone' == $a->objName ) {
1512
- if( 'vtimezone' != $b->objName ) return -1;
1513
- elseif( $a->srtk[0] <= $b->srtk[0] ) return -1;
1514
- else return 1;
1515
- }
1516
- elseif( 'vtimezone' == $b->objName ) return 1;
1517
- $sortkeys = array( 'year', 'month', 'day', 'hour', 'min', 'sec' );
1518
- for( $k = 0; $k < 4 ; $k++ ) {
1519
- if( empty( $a->srtk[$k] )) return -1;
1520
- elseif( empty( $b->srtk[$k] )) return 1;
1521
- if( is_array( $a->srtk[$k] )) {
1522
- if( is_array( $b->srtk[$k] )) {
1523
- foreach( $sortkeys as $key ) {
1524
- if ( empty( $a->srtk[$k][$key] )) return -1;
1525
- elseif( empty( $b->srtk[$k][$key] )) return 1;
1526
- if ( $a->srtk[$k][$key] == $b->srtk[$k][$key])
1527
- continue;
1528
- if (( (int) $a->srtk[$k][$key] ) < ((int) $b->srtk[$k][$key] ))
1529
- return -1;
1530
- elseif(( (int) $a->srtk[$k][$key] ) > ((int) $b->srtk[$k][$key] ))
1531
- return 1;
1532
- }
1533
- }
1534
- else return -1;
1535
- }
1536
- elseif( is_array( $b->srtk[$k] )) return 1;
1537
- elseif( $a->srtk[$k] < $b->srtk[$k] ) return -1;
1538
- elseif( $a->srtk[$k] > $b->srtk[$k] ) return 1;
1539
- }
1540
- return 0;
1541
- }
1542
- /**
1543
- * parse iCal text/file into vcalendar, components, properties and parameters
1544
- *
1545
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1546
- * @since 2.8.2 - 2011-05-21
1547
- * @param mixed $unparsedtext, optional, strict rfc2445 formatted, single property string or array of property strings
1548
- * @return bool FALSE if error occurs during parsing
1549
- *
1550
- */
1551
- function parse( $unparsedtext=FALSE ) {
1552
- $nl = $this->getConfig( 'nl' );
1553
- if(( FALSE === $unparsedtext ) || empty( $unparsedtext )) {
1554
- /* directory+filename is set previously via setConfig directory+filename or url */
1555
- if( FALSE === ( $filename = $this->getConfig( 'url' )))
1556
- $filename = $this->getConfig( 'dirfile' );
1557
- /* READ FILE */
1558
- if( FALSE === ( $rows = url_get_contents( $filename )))
1559
- return FALSE; /* err 1 */
1560
- }
1561
- elseif( is_array( $unparsedtext ))
1562
- $rows = implode( '\n'.$nl, $unparsedtext );
1563
- else
1564
- $rows = & $unparsedtext;
1565
- /* identify BEGIN:VCALENDAR, MUST be first row */
1566
- if( 'BEGIN:VCALENDAR' != strtoupper( substr( $rows, 0, 15 )))
1567
- return FALSE; /* err 8 */
1568
- /* fix line folding */
1569
- $eolchars = array( "\r\n", "\n\r", "\n", "\r" ); // check all line endings
1570
- $EOLmark = FALSE;
1571
- foreach( $eolchars as $eolchar ) {
1572
- if( !$EOLmark && ( FALSE !== strpos( $rows, $eolchar ))) {
1573
- $rows = str_replace( $eolchar." ", '', $rows );
1574
- $rows = str_replace( $eolchar."\t", '', $rows );
1575
- if( $eolchar != $nl )
1576
- $rows = str_replace( $eolchar, $nl, $rows );
1577
- $EOLmark = TRUE;
1578
- }
1579
- }
1580
- $tmp = explode( $nl, $rows );
1581
- $rows = array();
1582
- foreach( $tmp as $tmpr )
1583
- if( !empty( $tmpr ))
1584
- $rows[] = $tmpr;
1585
- /* skip trailing empty lines */
1586
- $lix = count( $rows ) - 1;
1587
- while( empty( $rows[$lix] ) && ( 0 < $lix ))
1588
- $lix -= 1;
1589
- /* identify ending END:VCALENDAR row, MUST be last row */
1590
- if( 'END:VCALENDAR' != strtoupper( substr( $rows[$lix], 0, 13 )))
1591
- return FALSE; /* err 9 */
1592
- if( 3 > count( $rows ))
1593
- return FALSE; /* err 10 */
1594
- $comp = & $this;
1595
- $calsync = 0;
1596
- /* identify components and update unparsed data within component */
1597
- $config = $this->getConfig();
1598
- foreach( $rows as $line ) {
1599
- if( '' == trim( $line ))
1600
- continue;
1601
- if( 'BEGIN:VCALENDAR' == strtoupper( substr( $line, 0, 15 ))) {
1602
- $calsync++;
1603
- continue;
1604
- }
1605
- elseif( 'END:VCALENDAR' == strtoupper( substr( $line, 0, 13 ))) {
1606
- $calsync--;
1607
- break;
1608
- }
1609
- elseif( 1 != $calsync )
1610
- return FALSE; /* err 20 */
1611
- elseif( in_array( strtoupper( substr( $line, 0, 6 )), array( 'END:VE', 'END:VF', 'END:VJ', 'END:VT' ))) {
1612
- $this->components[] = $comp->copy();
1613
- continue;
1614
- }
1615
-
1616
- if( 'BEGIN:VEVENT' == strtoupper( substr( $line, 0, 12 )))
1617
- $comp = new vevent( $config );
1618
- elseif( 'BEGIN:VFREEBUSY' == strtoupper( substr( $line, 0, 15 )))
1619
- $comp = new vfreebusy( $config );
1620
- elseif( 'BEGIN:VJOURNAL' == strtoupper( substr( $line, 0, 14 )))
1621
- $comp = new vjournal( $config );
1622
- elseif( 'BEGIN:VTODO' == strtoupper( substr( $line, 0, 11 )))
1623
- $comp = new vtodo( $config );
1624
- elseif( 'BEGIN:VTIMEZONE' == strtoupper( substr( $line, 0, 15 )))
1625
- $comp = new vtimezone( $config );
1626
- else /* update component with unparsed data */
1627
- $comp->unparsed[] = $line;
1628
- } // end - foreach( rows.. .
1629
- unset( $config );
1630
- /* parse data for calendar (this) object */
1631
- if( isset( $this->unparsed ) && is_array( $this->unparsed ) && ( 0 < count( $this->unparsed ))) {
1632
- /* concatenate property values spread over several lines */
1633
- $lastix = -1;
1634
- $propnames = array( 'calscale','method','prodid','version','x-' );
1635
- $proprows = array();
1636
- foreach( $this->unparsed as $line ) {
1637
- if( '' == trim( $line ))
1638
- continue;
1639
- $newProp = FALSE;
1640
- foreach ( $propnames as $propname ) {
1641
- if( $propname == strtolower( substr( $line, 0, strlen( $propname )))) {
1642
- $newProp = TRUE;
1643
- break;
1644
- }
1645
- }
1646
- if( $newProp ) {
1647
- $newProp = FALSE;
1648
- $lastix++;
1649
- $proprows[$lastix] = $line;
1650
- }
1651
- else
1652
- $proprows[$lastix] .= '!"#¤%&/()=?'.$line;
1653
- }
1654
- foreach( $proprows as $line ) {
1655
- $line = str_replace( '!"#¤%&/()=? ', '', $line );
1656
- $line = str_replace( '!"#¤%&/()=?', '', $line );
1657
- if( '\n' == substr( $line, -2 ))
1658
- $line = substr( $line, 0, strlen( $line ) - 2 );
1659
- /* get property name */
1660
- $cix = $propname = null;
1661
- for( $cix=0, $clen = strlen( $line ); $cix < $clen; $cix++ ) {
1662
- if( in_array( $line[$cix], array( ':', ';' )))
1663
- break;
1664
- else
1665
- $propname .= $line[$cix];
1666
- }
1667
- /* ignore version/prodid properties */
1668
- if( in_array( strtoupper( $propname ), array( 'VERSION', 'PRODID' )))
1669
- continue;
1670
- $line = substr( $line, $cix);
1671
- /* separate attributes from value */
1672
- $attr = array();
1673
- $attrix = -1;
1674
- $strlen = strlen( $line );
1675
- for( $cix=0; $cix < $strlen; $cix++ ) {
1676
- if(( ':' == $line[$cix] ) &&
1677
- ( '://' != substr( $line, $cix, 3 )) &&
1678
- ( !in_array( strtolower( substr( $line, $cix - 3, 4 )), array( 'fax:', 'cid:', 'sms:', 'tel:', 'urn:' ))) &&
1679
- ( !in_array( strtolower( substr( $line, $cix - 4, 5 )), array( 'crid:', 'news:', 'pres:' ))) &&
1680
- ( 'mailto:' != strtolower( substr( $line, $cix - 6, 7 )))) {
1681
- $attrEnd = TRUE;
1682
- if(( $cix < ( $strlen - 4 )) &&
1683
- ctype_digit( substr( $line, $cix+1, 4 ))) { // an URI with a (4pos) portnr??
1684
- for( $c2ix = $cix; 3 < $c2ix; $c2ix-- ) {
1685
- if( '://' == substr( $line, $c2ix - 2, 3 )) {
1686
- $attrEnd = FALSE;
1687
- break; // an URI with a portnr!!
1688
- }
1689
- }
1690
- }
1691
- if( $attrEnd) {
1692
- $line = substr( $line, $cix + 1 );
1693
- break;
1694
- }
1695
- }
1696
- if( ';' == $line[$cix] )
1697
- $attr[++$attrix] = null;
1698
- else
1699
- $attr[$attrix] .= $line[$cix];
1700
- }
1701
-
1702
- /* make attributes in array format */
1703
- $propattr = array();
1704
- foreach( $attr as $attribute ) {
1705
- $attrsplit = explode( '=', $attribute, 2 );
1706
- if( 1 < count( $attrsplit ))
1707
- $propattr[$attrsplit[0]] = $attrsplit[1];
1708
- else
1709
- $propattr[] = $attribute;
1710
- }
1711
- /* update Property */
1712
- if( FALSE !== strpos( $line, ',' )) {
1713
- $content = explode( ',', $line );
1714
- $clen = count( $content );
1715
- for( $cix = 0; $cix < $clen; $cix++ ) {
1716
- if( "\\" == substr( $content[$cix], -1 )) {
1717
- $content[$cix] .= ','.$content[$cix + 1];
1718
- unset( $content[$cix + 1] );
1719
- $cix++;
1720
- }
1721
- }
1722
- if( 1 < count( $content )) {
1723
- foreach( $content as $cix => $contentPart )
1724
- $content[$cix] = calendarComponent::_strunrep( $contentPart );
1725
- $this->setProperty( $propname, $content, $propattr );
1726
- continue;
1727
- }
1728
- else
1729
- $line = reset( $content );
1730
- $line = calendarComponent::_strunrep( $line );
1731
- }
1732
- $this->setProperty( $propname, trim( $line ), $propattr );
1733
- } // end - foreach( $this->unparsed.. .
1734
- } // end - if( is_array( $this->unparsed.. .
1735
- unset( $unparsedtext, $rows, $this->unparsed, $proprows );
1736
- /* parse Components */
1737
- if( is_array( $this->components ) && ( 0 < count( $this->components ))) {
1738
- $ckeys = array_keys( $this->components );
1739
- foreach( $ckeys as $ckey ) {
1740
- if( !empty( $this->components[$ckey] ) && !empty( $this->components[$ckey]->unparsed )) {
1741
- $this->components[$ckey]->parse();
1742
- }
1743
- }
1744
- }
1745
- else
1746
- return FALSE; /* err 91 or something.. . */
1747
- return TRUE;
1748
- }
1749
- /*********************************************************************************/
1750
- /**
1751
- * creates formatted output for calendar object instance
1752
- *
1753
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1754
- * @since 2.8.1 - 2011-03-12
1755
- * @return string
1756
- */
1757
- function createCalendar() {
1758
- $calendarInit1 = $calendarInit2 = $calendarxCaldecl = $calendarStart = $calendar = null;
1759
- switch( $this->format ) {
1760
- case 'xcal':
1761
- $calendarInit1 = '<?xml version="1.0" encoding="UTF-8"?>'.$this->nl.
1762
- '<!DOCTYPE iCalendar PUBLIC "-//IETF//DTD XCAL/iCalendar XML//EN"'.$this->nl.
1763
- '"http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-01.txt"';
1764
- $calendarInit2 = '>'.$this->nl;
1765
- $calendarStart = '<vcalendar';
1766
- break;
1767
- default:
1768
- $calendarStart = 'BEGIN:VCALENDAR'.$this->nl;
1769
- break;
1770
- }
1771
- $calendarStart .= $this->createVersion();
1772
- $calendarStart .= $this->createProdid();
1773
- $calendarStart .= $this->createCalscale();
1774
- $calendarStart .= $this->createMethod();
1775
- switch( $this->format ) {
1776
- case 'xcal':
1777
- $nlstrlen = strlen( $this->nl );
1778
- if( $this->nl == substr( $calendarStart, ( 0 - $nlstrlen )))
1779
- $calendarStart = substr( $calendarStart, 0, ( strlen( $calendarStart ) - $nlstrlen ));
1780
- $calendarStart .= '>'.$this->nl;
1781
- break;
1782
- default:
1783
- break;
1784
- }
1785
- $calendar .= $this->createXprop();
1786
- foreach( $this->components as $component ) {
1787
- if( empty( $component )) continue;
1788
- $component->setConfig( $this->getConfig(), FALSE, TRUE );
1789
- $calendar .= $component->createComponent( $this->xcaldecl );
1790
- }
1791
- if(( 0 < count( $this->xcaldecl )) && ( 'xcal' == $this->format )) { // xCal only
1792
- $calendarInit1 .= $this->nl.'['.$this->nl;
1793
- $old_xcaldecl = array();
1794
- foreach( $this->xcaldecl as $declix => $declPart ) {
1795
- if(( 0 < count( $old_xcaldecl)) &&
1796
- ( in_array( $declPart['uri'], $old_xcaldecl['uri'] )) &&
1797
- ( in_array( $declPart['external'], $old_xcaldecl['external'] )))
1798
- continue; // no duplicate uri and ext. references
1799
- $calendarxCaldecl .= '<!';
1800
- foreach( $declPart as $declKey => $declValue ) {
1801
- switch( $declKey ) { // index
1802
- case 'xmldecl': // no 1
1803
- $calendarxCaldecl .= $declValue.' ';
1804
- break;
1805
- case 'uri': // no 2
1806
- $calendarxCaldecl .= $declValue.' ';
1807
- $old_xcaldecl['uri'][] = $declValue;
1808
- break;
1809
- case 'ref': // no 3
1810
- $calendarxCaldecl .= $declValue.' ';
1811
- break;
1812
- case 'external': // no 4
1813
- $calendarxCaldecl .= '"'.$declValue.'" ';
1814
- $old_xcaldecl['external'][] = $declValue;
1815
- break;
1816
- case 'type': // no 5
1817
- $calendarxCaldecl .= $declValue.' ';
1818
- break;
1819
- case 'type2': // no 6
1820
- $calendarxCaldecl .= $declValue;
1821
- break;
1822
- }
1823
- }
1824
- $calendarxCaldecl .= '>'.$this->nl;
1825
- }
1826
- $calendarInit2 = ']'.$calendarInit2;
1827
- }
1828
- switch( $this->format ) {
1829
- case 'xcal':
1830
- $calendar .= '</vcalendar>'.$this->nl;
1831
- break;
1832
- default:
1833
- $calendar .= 'END:VCALENDAR'.$this->nl;
1834
- break;
1835
- }
1836
- return $calendarInit1.$calendarxCaldecl.$calendarInit2.$calendarStart.$calendar;
1837
- }
1838
- /**
1839
- * a HTTP redirect header is sent with created, updated and/or parsed calendar
1840
- *
1841
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1842
- * @since 2.9.12 - 2011-07-13
1843
- * @param bool $utf8Encode
1844
- * @param bool $gzip
1845
- * @return redirect
1846
- */
1847
- function returnCalendar( $utf8Encode=FALSE, $gzip=FALSE ) {
1848
- $filename = $this->getConfig( 'filename' );
1849
- $output = $this->createCalendar();
1850
- if( $utf8Encode )
1851
- $output = utf8_encode( $output );
1852
- if( $gzip ) {
1853
- $output = gzencode( $output, 9 );
1854
- header( 'Content-Encoding: gzip');
1855
- header( 'Vary: *');
1856
- }
1857
- $filesize = strlen( $output );
1858
- if( 'xcal' == $this->format )
1859
- header( 'Content-Type: application/calendar+xml; charset=utf-8' );
1860
- else
1861
- header( 'Content-Type: text/calendar; charset=utf-8' );
1862
- header( 'Content-Length: '.$filesize );
1863
- header( 'Content-Disposition: attachment; filename="'.$filename.'"' );
1864
- header( 'Cache-Control: max-age=10' );
1865
- echo $output;
1866
- die();
1867
- }
1868
- /**
1869
- * save content in a file
1870
- *
1871
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1872
- * @since 2.2.12 - 2007-12-30
1873
- * @param string $directory optional
1874
- * @param string $filename optional
1875
- * @param string $delimiter optional
1876
- * @return bool
1877
- */
1878
- function saveCalendar( $directory=FALSE, $filename=FALSE, $delimiter=FALSE ) {
1879
- if( $directory )
1880
- $this->setConfig( 'directory', $directory );
1881
- if( $filename )
1882
- $this->setConfig( 'filename', $filename );
1883
- if( $delimiter && ($delimiter != DIRECTORY_SEPARATOR ))
1884
- $this->setConfig( 'delimiter', $delimiter );
1885
- if( FALSE === ( $dirfile = $this->getConfig( 'url' )))
1886
- $dirfile = $this->getConfig( 'dirfile' );
1887
- $iCalFile = @fopen( $dirfile, 'w' );
1888
- if( $iCalFile ) {
1889
- if( FALSE === fwrite( $iCalFile, $this->createCalendar() ))
1890
- return FALSE;
1891
- fclose( $iCalFile );
1892
- return TRUE;
1893
- }
1894
- else
1895
- return FALSE;
1896
- }
1897
- /**
1898
- * if recent version of calendar file exists (default one hour), an HTTP redirect header is sent
1899
- * else FALSE is returned
1900
- *
1901
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1902
- * @since 2.2.12 - 2007-10-28
1903
- * @param string $directory optional alt. int timeout
1904
- * @param string $filename optional
1905
- * @param string $delimiter optional
1906
- * @param int timeout optional, default 3600 sec
1907
- * @return redirect/FALSE
1908
- */
1909
- function useCachedCalendar( $directory=FALSE, $filename=FALSE, $delimiter=FALSE, $timeout=3600) {
1910
- if ( $directory && ctype_digit( (string) $directory ) && !$filename ) {
1911
- $timeout = (int) $directory;
1912
- $directory = FALSE;
1913
- }
1914
- if( $directory )
1915
- $this->setConfig( 'directory', $directory );
1916
- if( $filename )
1917
- $this->setConfig( 'filename', $filename );
1918
- if( $delimiter && ( $delimiter != DIRECTORY_SEPARATOR ))
1919
- $this->setConfig( 'delimiter', $delimiter );
1920
- $filesize = $this->getConfig( 'filesize' );
1921
- if( 0 >= $filesize )
1922
- return FALSE;
1923
- $dirfile = $this->getConfig( 'dirfile' );
1924
- if( time() - filemtime( $dirfile ) < $timeout) {
1925
- clearstatcache();
1926
- $dirfile = $this->getConfig( 'dirfile' );
1927
- $filename = $this->getConfig( 'filename' );
1928
- // if( headers_sent( $filename, $linenum ))
1929
- // die( "Headers already sent in $filename on line $linenum\n" );
1930
- if( 'xcal' == $this->format )
1931
- header( 'Content-Type: application/calendar+xml; charset=utf-8' );
1932
- else
1933
- header( 'Content-Type: text/calendar; charset=utf-8' );
1934
- header( 'Content-Length: '.$filesize );
1935
- header( 'Content-Disposition: attachment; filename="'.$filename.'"' );
1936
- header( 'Cache-Control: max-age=10' );
1937
- $fp = @fopen( $dirfile, 'r' );
1938
- if( $fp ) {
1939
- fpassthru( $fp );
1940
- fclose( $fp );
1941
- }
1942
- die();
1943
- }
1944
- else
1945
- return FALSE;
1946
- }
1947
- }
1948
- /*********************************************************************************/
1949
- /*********************************************************************************/
1950
- /**
1951
- * abstract class for calendar components
1952
- *
1953
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1954
- * @since 2.9.6 - 2011-05-14
1955
- */
1956
- class calendarComponent {
1957
- // component property variables
1958
- var $uid;
1959
- var $dtstamp;
1960
-
1961
- // component config variables
1962
- var $allowEmpty;
1963
- var $language;
1964
- var $nl;
1965
- var $unique_id;
1966
- var $format;
1967
- var $objName; // created automatically at instance creation
1968
- var $dtzid; // default (local) timezone
1969
- // component internal variables
1970
- var $componentStart1;
1971
- var $componentStart2;
1972
- var $componentEnd1;
1973
- var $componentEnd2;
1974
- var $elementStart1;
1975
- var $elementStart2;
1976
- var $elementEnd1;
1977
- var $elementEnd2;
1978
- var $intAttrDelimiter;
1979
- var $attributeDelimiter;
1980
- var $valueInit;
1981
- // component xCal declaration container
1982
- var $xcaldecl;
1983
- /**
1984
- * constructor for calendar component object
1985
- *
1986
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1987
- * @since 2.9.6 - 2011-05-17
1988
- */
1989
- function calendarComponent() {
1990
- $this->objName = ( isset( $this->timezonetype )) ?
1991
- strtolower( $this->timezonetype ) : get_class ( $this );
1992
- $this->uid = array();
1993
- $this->dtstamp = array();
1994
-
1995
- $this->language = null;
1996
- $this->nl = null;
1997
- $this->unique_id = null;
1998
- $this->format = null;
1999
- $this->dtzid = null;
2000
- $this->allowEmpty = TRUE;
2001
- $this->xcaldecl = array();
2002
-
2003
- $this->_createFormat();
2004
- $this->_makeDtstamp();
2005
- }
2006
- /*********************************************************************************/
2007
- /**
2008
- * Property Name: ACTION
2009
- */
2010
- /**
2011
- * creates formatted output for calendar component property action
2012
- *
2013
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2014
- * @since 2.4.8 - 2008-10-22
2015
- * @return string
2016
- */
2017
- function createAction() {
2018
- if( empty( $this->action )) return FALSE;
2019
- if( empty( $this->action['value'] ))
2020
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'ACTION' ) : FALSE;
2021
- $attributes = $this->_createParams( $this->action['params'] );
2022
- return $this->_createElement( 'ACTION', $attributes, $this->action['value'] );
2023
- }
2024
- /**
2025
- * set calendar component property action
2026
- *
2027
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2028
- * @since 2.4.8 - 2008-11-04
2029
- * @param string $value "AUDIO" / "DISPLAY" / "EMAIL" / "PROCEDURE"
2030
- * @param mixed $params
2031
- * @return bool
2032
- */
2033
- function setAction( $value, $params=FALSE ) {
2034
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
2035
- $this->action = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
2036
- return TRUE;
2037
- }
2038
- /*********************************************************************************/
2039
- /**
2040
- * Property Name: ATTACH
2041
- */
2042
- /**
2043
- * creates formatted output for calendar component property attach
2044
- *
2045
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2046
- * @since 0.9.7 - 2006-11-23
2047
- * @return string
2048
- */
2049
- function createAttach() {
2050
- if( empty( $this->attach )) return FALSE;
2051
- $output = null;
2052
- foreach( $this->attach as $attachPart ) {
2053
- if(! empty( $attachPart['value'] )) {
2054
- $attributes = $this->_createParams( $attachPart['params'] );
2055
- $output .= $this->_createElement( 'ATTACH', $attributes, $attachPart['value'] );
2056
- }
2057
- elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'ATTACH' );
2058
- }
2059
- return $output;
2060
- }
2061
- /**
2062
- * set calendar component property attach
2063
- *
2064
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2065
- * @since 2.5.1 - 2008-11-06
2066
- * @param string $value
2067
- * @param array $params, optional
2068
- * @param integer $index, optional
2069
- * @return bool
2070
- */
2071
- function setAttach( $value, $params=FALSE, $index=FALSE ) {
2072
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
2073
- iCalUtilityFunctions::_setMval( $this->attach, $value, $params, FALSE, $index );
2074
- return TRUE;
2075
- }
2076
- /*********************************************************************************/
2077
- /**
2078
- * Property Name: ATTENDEE
2079
- */
2080
- /**
2081
- * creates formatted output for calendar component property attendee
2082
- *
2083
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2084
- * @since 2.9.8 - 2011-05-30
2085
- * @return string
2086
- */
2087
- function createAttendee() {
2088
- if( empty( $this->attendee )) return FALSE;
2089
- $output = null;
2090
- foreach( $this->attendee as $attendeePart ) { // start foreach 1
2091
- if( empty( $attendeePart['value'] )) {
2092
- if( $this->getConfig( 'allowEmpty' ))
2093
- $output .= $this->_createElement( 'ATTENDEE' );
2094
- continue;
2095
- }
2096
- $attendee1 = $attendee2 = null;
2097
- foreach( $attendeePart as $paramlabel => $paramvalue ) { // start foreach 2
2098
- if( 'value' == $paramlabel )
2099
- $attendee2 .= $paramvalue;
2100
- elseif(( 'params' == $paramlabel ) && ( is_array( $paramvalue ))) { // start elseif
2101
- // set attenddee parameters in rfc2445 order
2102
- if( isset( $paramvalue['CUTYPE'] ))
2103
- $attendee1 .= $this->intAttrDelimiter.'CUTYPE='.$paramvalue['CUTYPE'];
2104
- if( isset( $paramvalue['MEMBER'] )) {
2105
- $attendee1 .= $this->intAttrDelimiter.'MEMBER=';
2106
- foreach( $paramvalue['MEMBER'] as $cix => $opv )
2107
- $attendee1 .= ( $cix ) ? ', "'.$opv.'"' : '"'.$opv.'"' ;
2108
- }
2109
- if( isset( $paramvalue['ROLE'] ))
2110
- $attendee1 .= $this->intAttrDelimiter.'ROLE='.$paramvalue['ROLE'];
2111
- if( isset( $paramvalue['PARTSTAT'] ))
2112
- $attendee1 .= $this->intAttrDelimiter.'PARTSTAT='.$paramvalue['PARTSTAT'];
2113
- if( isset( $paramvalue['RSVP'] ))
2114
- $attendee1 .= $this->intAttrDelimiter.'RSVP='.$paramvalue['RSVP'];
2115
- if( isset( $paramvalue['DELEGATED-TO'] )) {
2116
- $attendee1 .= $this->intAttrDelimiter.'DELEGATED-TO=';
2117
- foreach( $paramvalue['DELEGATED-TO'] as $cix => $opv )
2118
- $attendee1 .= ( $cix ) ? ', "'.$opv.'"' : '"'.$opv.'"' ;
2119
- }
2120
- if( isset( $paramvalue['DELEGATED-FROM'] )) {
2121
- $attendee1 .= $this->intAttrDelimiter.'DELEGATED-FROM=';
2122
- foreach( $paramvalue['DELEGATED-FROM'] as $cix => $opv )
2123
- $attendee1 .= ( $cix ) ? ', "'.$opv.'"' : '"'.$opv.'"' ;
2124
- }
2125
- if( isset( $paramvalue['SENT-BY'] ))
2126
- $attendee1 .= $this->intAttrDelimiter.'SENT-BY="'.$paramvalue['SENT-BY'].'"';
2127
- if( isset( $paramvalue['CN'] ))
2128
- $attendee1 .= $this->intAttrDelimiter.'CN="'.$paramvalue['CN'].'"';
2129
- if( isset( $paramvalue['DIR'] ))
2130
- $attendee1 .= $this->intAttrDelimiter.'DIR="'.$paramvalue['DIR'].'"';
2131
- if( isset( $paramvalue['LANGUAGE'] ))
2132
- $attendee1 .= $this->intAttrDelimiter.'LANGUAGE='.$paramvalue['LANGUAGE'];
2133
- $xparams = array();
2134
- foreach( $paramvalue as $optparamlabel => $optparamvalue ) { // start foreach 3
2135
- if( ctype_digit( (string) $optparamlabel )) {
2136
- $xparams[] = $optparamvalue;
2137
- continue;
2138
- }
2139
- if( !in_array( $optparamlabel, array( 'CUTYPE', 'MEMBER', 'ROLE', 'PARTSTAT', 'RSVP', 'DELEGATED-TO', 'DELEGATED-FROM', 'SENT-BY', 'CN', 'DIR', 'LANGUAGE' )))
2140
- $xparams[$optparamlabel] = $optparamvalue;
2141
- } // end foreach 3
2142
- ksort( $xparams, SORT_STRING );
2143
- foreach( $xparams as $paramKey => $paramValue ) {
2144
- if( ctype_digit( (string) $paramKey ))
2145
- $attendee1 .= $this->intAttrDelimiter.$paramValue;
2146
- else
2147
- $attendee1 .= $this->intAttrDelimiter."$paramKey=$paramValue";
2148
- } // end foreach 3
2149
- } // end elseif(( 'params' == $paramlabel ) && ( is_array( $paramvalue )))
2150
- } // end foreach 2
2151
- $output .= $this->_createElement( 'ATTENDEE', $attendee1, $attendee2 );
2152
- } // end foreach 1
2153
- return $output;
2154
- }
2155
- /**
2156
- * set calendar component property attach
2157
- *
2158
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2159
- * @since 2.6.34 - 2010-12-18
2160
- * @param string $value
2161
- * @param array $params, optional
2162
- * @param integer $index, optional
2163
- * @return bool
2164
- */
2165
- function setAttendee( $value, $params=FALSE, $index=FALSE ) {
2166
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
2167
- // ftp://, http://, mailto:, file://, gopher://, news:, nntp://, telnet://, wais://, prospero:// may exist.. . also in params
2168
- if( FALSE !== ( $pos = strpos( substr( $value, 0, 9 ), ':' )))
2169
- $value = strtoupper( substr( $value, 0, $pos )).substr( $value, $pos );
2170
- elseif( !empty( $value ))
2171
- $value = 'MAILTO:'.$value;
2172
- $params2 = array();
2173
- if( is_array($params )) {
2174
- $optarrays = array();
2175
- foreach( $params as $optparamlabel => $optparamvalue ) {
2176
- $optparamlabel = strtoupper( $optparamlabel );
2177
- switch( $optparamlabel ) {
2178
- case 'MEMBER':
2179
- case 'DELEGATED-TO':
2180
- case 'DELEGATED-FROM':
2181
- if( !is_array( $optparamvalue ))
2182
- $optparamvalue = array( $optparamvalue );
2183
- foreach( $optparamvalue as $part ) {
2184
- $part = trim( $part );
2185
- if(( '"' == substr( $part, 0, 1 )) &&
2186
- ( '"' == substr( $part, -1 )))
2187
- $part = substr( $part, 1, ( strlen( $part ) - 2 ));
2188
- if( 'mailto:' != strtolower( substr( $part, 0, 7 )))
2189
- $part = "MAILTO:$part";
2190
- else
2191
- $part = 'MAILTO:'.substr( $part, 7 );
2192
- $optarrays[$optparamlabel][] = $part;
2193
- }
2194
- break;
2195
- default:
2196
- if(( '"' == substr( $optparamvalue, 0, 1 )) &&
2197
- ( '"' == substr( $optparamvalue, -1 )))
2198
- $optparamvalue = substr( $optparamvalue, 1, ( strlen( $optparamvalue ) - 2 ));
2199
- if( 'SENT-BY' == $optparamlabel ) {
2200
- if( 'mailto:' != strtolower( substr( $optparamvalue, 0, 7 )))
2201
- $optparamvalue = "MAILTO:$optparamvalue";
2202
- else
2203
- $optparamvalue = 'MAILTO:'.substr( $optparamvalue, 7 );
2204
- }
2205
- $params2[$optparamlabel] = $optparamvalue;
2206
- break;
2207
- } // end switch( $optparamlabel.. .
2208
- } // end foreach( $optparam.. .
2209
- foreach( $optarrays as $optparamlabel => $optparams )
2210
- $params2[$optparamlabel] = $optparams;
2211
- }
2212
- // remove defaults
2213
- iCalUtilityFunctions::_existRem( $params2, 'CUTYPE', 'INDIVIDUAL' );
2214
- iCalUtilityFunctions::_existRem( $params2, 'PARTSTAT', 'NEEDS-ACTION' );
2215
- iCalUtilityFunctions::_existRem( $params2, 'ROLE', 'REQ-PARTICIPANT' );
2216
- iCalUtilityFunctions::_existRem( $params2, 'RSVP', 'FALSE' );
2217
- // check language setting
2218
- if( isset( $params2['CN' ] )) {
2219
- $lang = $this->getConfig( 'language' );
2220
- if( !isset( $params2['LANGUAGE' ] ) && !empty( $lang ))
2221
- $params2['LANGUAGE' ] = $lang;
2222
- }
2223
- iCalUtilityFunctions::_setMval( $this->attendee, $value, $params2, FALSE, $index );
2224
- return TRUE;
2225
- }
2226
- /*********************************************************************************/
2227
- /**
2228
- * Property Name: CATEGORIES
2229
- */
2230
- /**
2231
- * creates formatted output for calendar component property categories
2232
- *
2233
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2234
- * @since 2.4.8 - 2008-10-22
2235
- * @return string
2236
- */
2237
- function createCategories() {
2238
- if( empty( $this->categories )) return FALSE;
2239
- $output = null;
2240
- foreach( $this->categories as $category ) {
2241
- if( empty( $category['value'] )) {
2242
- if ( $this->getConfig( 'allowEmpty' ))
2243
- $output .= $this->_createElement( 'CATEGORIES' );
2244
- continue;
2245
- }
2246
- $attributes = $this->_createParams( $category['params'], array( 'LANGUAGE' ));
2247
- if( is_array( $category['value'] )) {
2248
- foreach( $category['value'] as $cix => $categoryPart )
2249
- $category['value'][$cix] = $this->_strrep( $categoryPart );
2250
- $content = implode( ',', $category['value'] );
2251
- }
2252
- else
2253
- $content = $this->_strrep( $category['value'] );
2254
- $output .= $this->_createElement( 'CATEGORIES', $attributes, $content );
2255
- }
2256
- return $output;
2257
- }
2258
- /**
2259
- * set calendar component property categories
2260
- *
2261
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2262
- * @since 2.5.1 - 2008-11-06
2263
- * @param mixed $value
2264
- * @param array $params, optional
2265
- * @param integer $index, optional
2266
- * @return bool
2267
- */
2268
- function setCategories( $value, $params=FALSE, $index=FALSE ) {
2269
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
2270
- iCalUtilityFunctions::_setMval( $this->categories, $value, $params, FALSE, $index );
2271
- return TRUE;
2272
- }
2273
- /*********************************************************************************/
2274
- /**
2275
- * Property Name: CLASS
2276
- */
2277
- /**
2278
- * creates formatted output for calendar component property class
2279
- *
2280
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2281
- * @since 0.9.7 - 2006-11-20
2282
- * @return string
2283
- */
2284
- function createClass() {
2285
- if( empty( $this->class )) return FALSE;
2286
- if( empty( $this->class['value'] ))
2287
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'CLASS' ) : FALSE;
2288
- $attributes = $this->_createParams( $this->class['params'] );
2289
- return $this->_createElement( 'CLASS', $attributes, $this->class['value'] );
2290
- }
2291
- /**
2292
- * set calendar component property class
2293
- *
2294
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2295
- * @since 2.4.8 - 2008-11-04
2296
- * @param string $value "PUBLIC" / "PRIVATE" / "CONFIDENTIAL" / iana-token / x-name
2297
- * @param array $params optional
2298
- * @return bool
2299
- */
2300
- function setClass( $value, $params=FALSE ) {
2301
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
2302
- $this->class = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
2303
- return TRUE;
2304
- }
2305
- /*********************************************************************************/
2306
- /**
2307
- * Property Name: COMMENT
2308
- */
2309
- /**
2310
- * creates formatted output for calendar component property comment
2311
- *
2312
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2313
- * @since 2.4.8 - 2008-10-22
2314
- * @return string
2315
- */
2316
- function createComment() {
2317
- if( empty( $this->comment )) return FALSE;
2318
- $output = null;
2319
- foreach( $this->comment as $commentPart ) {
2320
- if( empty( $commentPart['value'] )) {
2321
- if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'COMMENT' );
2322
- continue;
2323
- }
2324
- $attributes = $this->_createParams( $commentPart['params'], array( 'ALTREP', 'LANGUAGE' ));
2325
- $content = $this->_strrep( $commentPart['value'] );
2326
- $output .= $this->_createElement( 'COMMENT', $attributes, $content );
2327
- }
2328
- return $output;
2329
- }
2330
- /**
2331
- * set calendar component property comment
2332
- *
2333
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2334
- * @since 2.5.1 - 2008-11-06
2335
- * @param string $value
2336
- * @param array $params, optional
2337
- * @param integer $index, optional
2338
- * @return bool
2339
- */
2340
- function setComment( $value, $params=FALSE, $index=FALSE ) {
2341
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
2342
- iCalUtilityFunctions::_setMval( $this->comment, $value, $params, FALSE, $index );
2343
- return TRUE;
2344
- }
2345
- /*********************************************************************************/
2346
- /**
2347
- * Property Name: COMPLETED
2348
- */
2349
- /**
2350
- * creates formatted output for calendar component property completed
2351
- *
2352
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2353
- * @since 2.4.8 - 2008-10-22
2354
- * @return string
2355
- */
2356
- function createCompleted( ) {
2357
- if( empty( $this->completed )) return FALSE;
2358
- if( !isset( $this->completed['value']['year'] ) &&
2359
- !isset( $this->completed['value']['month'] ) &&
2360
- !isset( $this->completed['value']['day'] ) &&
2361
- !isset( $this->completed['value']['hour'] ) &&
2362
- !isset( $this->completed['value']['min'] ) &&
2363
- !isset( $this->completed['value']['sec'] ))
2364
- if( $this->getConfig( 'allowEmpty' ))
2365
- return $this->_createElement( 'COMPLETED' );
2366
- else return FALSE;
2367
- $formatted = iCalUtilityFunctions::_format_date_time( $this->completed['value'], 7 );
2368
- $attributes = $this->_createParams( $this->completed['params'] );
2369
- return $this->_createElement( 'COMPLETED', $attributes, $formatted );
2370
- }
2371
- /**
2372
- * set calendar component property completed
2373
- *
2374
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2375
- * @since 2.4.8 - 2008-10-23
2376
- * @param mixed $year
2377
- * @param mixed $month optional
2378
- * @param int $day optional
2379
- * @param int $hour optional
2380
- * @param int $min optional
2381
- * @param int $sec optional
2382
- * @param array $params optional
2383
- * @return bool
2384
- */
2385
- function setCompleted( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
2386
- if( empty( $year )) {
2387
- if( $this->getConfig( 'allowEmpty' )) {
2388
- $this->completed = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params ));
2389
- return TRUE;
2390
- }
2391
- else
2392
- return FALSE;
2393
- }
2394
- $this->completed = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
2395
- return TRUE;
2396
- }
2397
- /*********************************************************************************/
2398
- /**
2399
- * Property Name: CONTACT
2400
- */
2401
- /**
2402
- * creates formatted output for calendar component property contact
2403
- *
2404
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2405
- * @since 2.4.8 - 2008-10-23
2406
- * @return string
2407
- */
2408
- function createContact() {
2409
- if( empty( $this->contact )) return FALSE;
2410
- $output = null;
2411
- foreach( $this->contact as $contact ) {
2412
- if( !empty( $contact['value'] )) {
2413
- $attributes = $this->_createParams( $contact['params'], array( 'ALTREP', 'LANGUAGE' ));
2414
- $content = $this->_strrep( $contact['value'] );
2415
- $output .= $this->_createElement( 'CONTACT', $attributes, $content );
2416
- }
2417
- elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'CONTACT' );
2418
- }
2419
- return $output;
2420
- }
2421
- /**
2422
- * set calendar component property contact
2423
- *
2424
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2425
- * @since 2.5.1 - 2008-11-05
2426
- * @param string $value
2427
- * @param array $params, optional
2428
- * @param integer $index, optional
2429
- * @return bool
2430
- */
2431
- function setContact( $value, $params=FALSE, $index=FALSE ) {
2432
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
2433
- iCalUtilityFunctions::_setMval( $this->contact, $value, $params, FALSE, $index );
2434
- return TRUE;
2435
- }
2436
- /*********************************************************************************/
2437
- /**
2438
- * Property Name: CREATED
2439
- */
2440
- /**
2441
- * creates formatted output for calendar component property created
2442
- *
2443
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2444
- * @since 2.4.8 - 2008-10-21
2445
- * @return string
2446
- */
2447
- function createCreated() {
2448
- if( empty( $this->created )) return FALSE;
2449
- $formatted = iCalUtilityFunctions::_format_date_time( $this->created['value'], 7 );
2450
- $attributes = $this->_createParams( $this->created['params'] );
2451
- return $this->_createElement( 'CREATED', $attributes, $formatted );
2452
- }
2453
- /**
2454
- * set calendar component property created
2455
- *
2456
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2457
- * @since 2.4.8 - 2008-10-23
2458
- * @param mixed $year optional
2459
- * @param mixed $month optional
2460
- * @param int $day optional
2461
- * @param int $hour optional
2462
- * @param int $min optional
2463
- * @param int $sec optional
2464
- * @param mixed $params optional
2465
- * @return bool
2466
- */
2467
- function setCreated( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
2468
- if( !isset( $year )) {
2469
- $year = date('Ymd\THis', mktime( date( 'H' ), date( 'i' ), date( 's' ) - date( 'Z'), date( 'm' ), date( 'd' ), date( 'Y' )));
2470
- }
2471
- $this->created = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
2472
- return TRUE;
2473
- }
2474
- /*********************************************************************************/
2475
- /**
2476
- * Property Name: DESCRIPTION
2477
- */
2478
- /**
2479
- * creates formatted output for calendar component property description
2480
- *
2481
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2482
- * @since 2.4.8 - 2008-10-22
2483
- * @return string
2484
- */
2485
- function createDescription() {
2486
- if( empty( $this->description )) return FALSE;
2487
- $output = null;
2488
- foreach( $this->description as $description ) {
2489
- if( !empty( $description['value'] )) {
2490
- $attributes = $this->_createParams( $description['params'], array( 'ALTREP', 'LANGUAGE' ));
2491
- $content = $this->_strrep( $description['value'] );
2492
- $output .= $this->_createElement( 'DESCRIPTION', $attributes, $content );
2493
- }
2494
- elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'DESCRIPTION' );
2495
- }
2496
- return $output;
2497
- }
2498
- /**
2499
- * set calendar component property description
2500
- *
2501
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2502
- * @since 2.6.24 - 2010-11-06
2503
- * @param string $value
2504
- * @param array $params, optional
2505
- * @param integer $index, optional
2506
- * @return bool
2507
- */
2508
- function setDescription( $value, $params=FALSE, $index=FALSE ) {
2509
- if( empty( $value )) { if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; }
2510
- if( 'vjournal' != $this->objName )
2511
- $index = 1;
2512
- iCalUtilityFunctions::_setMval( $this->description, $value, $params, FALSE, $index );
2513
- return TRUE;
2514
- }
2515
- /*********************************************************************************/
2516
- /**
2517
- * Property Name: DTEND
2518
- */
2519
- /**
2520
- * creates formatted output for calendar component property dtend
2521
- *
2522
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2523
- * @since 2.9.6 - 2011-05-14
2524
- * @return string
2525
- */
2526
- function createDtend() {
2527
- if( empty( $this->dtend )) return FALSE;
2528
- if( !isset( $this->dtend['value']['year'] ) &&
2529
- !isset( $this->dtend['value']['month'] ) &&
2530
- !isset( $this->dtend['value']['day'] ) &&
2531
- !isset( $this->dtend['value']['hour'] ) &&
2532
- !isset( $this->dtend['value']['min'] ) &&
2533
- !isset( $this->dtend['value']['sec'] ))
2534
- if( $this->getConfig( 'allowEmpty' ))
2535
- return $this->_createElement( 'DTEND' );
2536
- else return FALSE;
2537
- $formatted = iCalUtilityFunctions::_format_date_time( $this->dtend['value'] );
2538
- if(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
2539
- ( !isset( $this->dtend['params']['VALUE'] ) || ( $this->dtend['params']['VALUE'] != 'DATE' )) &&
2540
- !isset( $this->dtend['params']['TZID'] ))
2541
- $this->dtend['params']['TZID'] = $tzid;
2542
- $attributes = $this->_createParams( $this->dtend['params'] );
2543
- return $this->_createElement( 'DTEND', $attributes, $formatted );
2544
- }
2545
- /**
2546
- * set calendar component property dtend
2547
- *
2548
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2549
- * @since 2.9.6 - 2011-05-14
2550
- * @param mixed $year
2551
- * @param mixed $month optional
2552
- * @param int $day optional
2553
- * @param int $hour optional
2554
- * @param int $min optional
2555
- * @param int $sec optional
2556
- * @param string $tz optional
2557
- * @param array params optional
2558
- * @return bool
2559
- */
2560
- function setDtend( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
2561
- if( empty( $year )) {
2562
- if( $this->getConfig( 'allowEmpty' )) {
2563
- $this->dtend = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params ));
2564
- return TRUE;
2565
- }
2566
- else
2567
- return FALSE;
2568
- }
2569
- $this->dtend = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig( 'TZID' ));
2570
- return TRUE;
2571
- }
2572
- /*********************************************************************************/
2573
- /**
2574
- * Property Name: DTSTAMP
2575
- */
2576
- /**
2577
- * creates formatted output for calendar component property dtstamp
2578
- *
2579
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2580
- * @since 2.4.4 - 2008-03-07
2581
- * @return string
2582
- */
2583
- function createDtstamp() {
2584
- if( !isset( $this->dtstamp['value']['year'] ) &&
2585
- !isset( $this->dtstamp['value']['month'] ) &&
2586
- !isset( $this->dtstamp['value']['day'] ) &&
2587
- !isset( $this->dtstamp['value']['hour'] ) &&
2588
- !isset( $this->dtstamp['value']['min'] ) &&
2589
- !isset( $this->dtstamp['value']['sec'] ))
2590
- $this->_makeDtstamp();
2591
- $formatted = iCalUtilityFunctions::_format_date_time( $this->dtstamp['value'], 7 );
2592
- $attributes = $this->_createParams( $this->dtstamp['params'] );
2593
- return $this->_createElement( 'DTSTAMP', $attributes, $formatted );
2594
- }
2595
- /**
2596
- * computes datestamp for calendar component object instance dtstamp
2597
- *
2598
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2599
- * @since 2.6.25 - 2010-11-09
2600
- * @return void
2601
- */
2602
- function _makeDtstamp() {
2603
- $d = mktime( date('H'), date('m'), (date('s') - date( 'Z' )), date('m'), date('d'), date('Y'));
2604
- $this->dtstamp['value'] = array( 'year' => date( 'Y', $d )
2605
- , 'month' => date( 'm', $d )
2606
- , 'day' => date( 'd', $d )
2607
- , 'hour' => date( 'H', $d )
2608
- , 'min' => date( 'i', $d )
2609
- , 'sec' => date( 's', $d ));
2610
- $this->dtstamp['params'] = null;
2611
- }
2612
- /**
2613
- * set calendar component property dtstamp
2614
- *
2615
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2616
- * @since 2.4.8 - 2008-10-23
2617
- * @param mixed $year
2618
- * @param mixed $month optional
2619
- * @param int $day optional
2620
- * @param int $hour optional
2621
- * @param int $min optional
2622
- * @param int $sec optional
2623
- * @param array $params optional
2624
- * @return TRUE
2625
- */
2626
- function setDtstamp( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
2627
- if( empty( $year ))
2628
- $this->_makeDtstamp();
2629
- else
2630
- $this->dtstamp = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
2631
- return TRUE;
2632
- }
2633
- /*********************************************************************************/
2634
- /**
2635
- * Property Name: DTSTART
2636
- */
2637
- /**
2638
- * creates formatted output for calendar component property dtstart
2639
- *
2640
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2641
- * @since 2.9.6 - 2011-05-15
2642
- * @return string
2643
- */
2644
- function createDtstart() {
2645
- if( empty( $this->dtstart )) return FALSE;
2646
- if( !isset( $this->dtstart['value']['year'] ) &&
2647
- !isset( $this->dtstart['value']['month'] ) &&
2648
- !isset( $this->dtstart['value']['day'] ) &&
2649
- !isset( $this->dtstart['value']['hour'] ) &&
2650
- !isset( $this->dtstart['value']['min'] ) &&
2651
- !isset( $this->dtstart['value']['sec'] )) {
2652
- if( $this->getConfig( 'allowEmpty' ))
2653
- return $this->_createElement( 'DTSTART' );
2654
- else return FALSE;
2655
- }
2656
- if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' )))
2657
- unset( $this->dtstart['value']['tz'], $this->dtstart['params']['TZID'] );
2658
- elseif(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
2659
- ( !isset( $this->dtstart['params']['VALUE'] ) || ( $this->dtstart['params']['VALUE'] != 'DATE' )) &&
2660
- !isset( $this->dtstart['params']['TZID'] ))
2661
- $this->dtstart['params']['TZID'] = $tzid;
2662
- $formatted = iCalUtilityFunctions::_format_date_time( $this->dtstart['value'] );
2663
- $attributes = $this->_createParams( $this->dtstart['params'] );
2664
- return $this->_createElement( 'DTSTART', $attributes, $formatted );
2665
- }
2666
- /**
2667
- * set calendar component property dtstart
2668
- *
2669
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2670
- * @since 2.6.22 - 2010-09-22
2671
- * @param mixed $year
2672
- * @param mixed $month optional
2673
- * @param int $day optional
2674
- * @param int $hour optional
2675
- * @param int $min optional
2676
- * @param int $sec optional
2677
- * @param string $tz optional
2678
- * @param array $params optional
2679
- * @return bool
2680
- */
2681
- function setDtstart( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
2682
- if( empty( $year )) {
2683
- if( $this->getConfig( 'allowEmpty' )) {
2684
- $this->dtstart = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params ));
2685
- return TRUE;
2686
- }
2687
- else
2688
- return FALSE;
2689
- }
2690
- $this->dtstart = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, 'dtstart', $this->objName, $this->getConfig( 'TZID' ));
2691
- return TRUE;
2692
- }
2693
- /*********************************************************************************/
2694
- /**
2695
- * Property Name: DUE
2696
- */
2697
- /**
2698
- * creates formatted output for calendar component property due
2699
- *
2700
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2701
- * @since 2.4.8 - 2008-10-22
2702
- * @return string
2703
- */
2704
- function createDue() {
2705
- if( empty( $this->due )) return FALSE;
2706
- if( !isset( $this->due['value']['year'] ) &&
2707
- !isset( $this->due['value']['month'] ) &&
2708
- !isset( $this->due['value']['day'] ) &&
2709
- !isset( $this->due['value']['hour'] ) &&
2710
- !isset( $this->due['value']['min'] ) &&
2711
- !isset( $this->due['value']['sec'] )) {
2712
- if( $this->getConfig( 'allowEmpty' ))
2713
- return $this->_createElement( 'DUE' );
2714
- else
2715
- return FALSE;
2716
- }
2717
- $formatted = iCalUtilityFunctions::_format_date_time( $this->due['value'] );
2718
- if(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
2719
- ( !isset( $this->due['params']['VALUE'] ) || ( $this->due['params']['VALUE'] != 'DATE' )) &&
2720
- !isset( $this->due['params']['TZID'] ))
2721
- $this->due['params']['TZID'] = $tzid;
2722
- $attributes = $this->_createParams( $this->due['params'] );
2723
- return $this->_createElement( 'DUE', $attributes, $formatted );
2724
- }
2725
- /**
2726
- * set calendar component property due
2727
- *
2728
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2729
- * @since 2.4.8 - 2008-11-04
2730
- * @param mixed $year
2731
- * @param mixed $month optional
2732
- * @param int $day optional
2733
- * @param int $hour optional
2734
- * @param int $min optional
2735
- * @param int $sec optional
2736
- * @param array $params optional
2737
- * @return bool
2738
- */
2739
- function setDue( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
2740
- if( empty( $year )) {
2741
- if( $this->getConfig( 'allowEmpty' )) {
2742
- $this->due = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params ));
2743
- return TRUE;
2744
- }
2745
- else
2746
- return FALSE;
2747
- }
2748
- $this->due = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig( 'TZID' ));
2749
- return TRUE;
2750
- }
2751
- /*********************************************************************************/
2752
- /**
2753
- * Property Name: DURATION
2754
- */
2755
- /**
2756
- * creates formatted output for calendar component property duration
2757
- *
2758
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2759
- * @since 2.4.8 - 2008-10-21
2760
- * @return string
2761
- */
2762
- function createDuration() {
2763
- if( empty( $this->duration )) return FALSE;
2764
- if( !isset( $this->duration['value']['week'] ) &&
2765
- !isset( $this->duration['value']['day'] ) &&
2766
- !isset( $this->duration['value']['hour'] ) &&
2767
- !isset( $this->duration['value']['min'] ) &&
2768
- !isset( $this->duration['value']['sec'] ))
2769
- if( $this->getConfig( 'allowEmpty' ))
2770
- return $this->_createElement( 'DURATION', array(), null );
2771
- else return FALSE;
2772
- $attributes = $this->_createParams( $this->duration['params'] );
2773
- return $this->_createElement( 'DURATION', $attributes, iCalUtilityFunctions::_format_duration( $this->duration['value'] ));
2774
- }
2775
- /**
2776
- * set calendar component property duration
2777
- *
2778
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2779
- * @since 2.4.8 - 2008-11-04
2780
- * @param mixed $week
2781
- * @param mixed $day optional
2782
- * @param int $hour optional
2783
- * @param int $min optional
2784
- * @param int $sec optional
2785
- * @param array $params optional
2786
- * @return bool
2787
- */
2788
- function setDuration( $week, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
2789
- if( empty( $week )) if( $this->getConfig( 'allowEmpty' )) $week = null; else return FALSE;
2790
- if( is_array( $week ) && ( 1 <= count( $week )))
2791
- $this->duration = array( 'value' => iCalUtilityFunctions::_duration_array( $week ), 'params' => iCalUtilityFunctions::_setParams( $day ));
2792
- elseif( is_string( $week ) && ( 3 <= strlen( trim( $week )))) {
2793
- $week = trim( $week );
2794
- if( in_array( substr( $week, 0, 1 ), array( '+', '-' )))
2795
- $week = substr( $week, 1 );
2796
- $this->duration = array( 'value' => iCalUtilityFunctions::_duration_string( $week ), 'params' => iCalUtilityFunctions::_setParams( $day ));
2797
- }
2798
- elseif( empty( $week ) && empty( $day ) && empty( $hour ) && empty( $min ) && empty( $sec ))
2799
- return FALSE;
2800
- else
2801
- $this->duration = array( 'value' => iCalUtilityFunctions::_duration_array( array( $week, $day, $hour, $min, $sec )), 'params' => iCalUtilityFunctions::_setParams( $params ));
2802
- return TRUE;
2803
- }
2804
- /*********************************************************************************/
2805
- /**
2806
- * Property Name: EXDATE
2807
- */
2808
- /**
2809
- * creates formatted output for calendar component property exdate
2810
- *
2811
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2812
- * @since 2.4.8 - 2008-10-22
2813
- * @return string
2814
- */
2815
- function createExdate() {
2816
- if( empty( $this->exdate )) return FALSE;
2817
- $output = null;
2818
- foreach( $this->exdate as $ex => $theExdate ) {
2819
- if( empty( $theExdate['value'] )) {
2820
- if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'EXDATE' );
2821
- continue;
2822
- }
2823
- $content = $attributes = null;
2824
- foreach( $theExdate['value'] as $eix => $exdatePart ) {
2825
- $parno = count( $exdatePart );
2826
- $formatted = iCalUtilityFunctions::_format_date_time( $exdatePart, $parno );
2827
- if( isset( $theExdate['params']['TZID'] ))
2828
- $formatted = str_replace( 'Z', '', $formatted);
2829
- if( 0 < $eix ) {
2830
- if( isset( $theExdate['value'][0]['tz'] )) {
2831
- if( ctype_digit( substr( $theExdate['value'][0]['tz'], -4 )) ||
2832
- ( 'Z' == $theExdate['value'][0]['tz'] )) {
2833
- if( 'Z' != substr( $formatted, -1 ))
2834
- $formatted .= 'Z';
2835
- }
2836
- else
2837
- $formatted = str_replace( 'Z', '', $formatted );
2838
- }
2839
- else
2840
- $formatted = str_replace( 'Z', '', $formatted );
2841
- }
2842
- $content .= ( 0 < $eix ) ? ','.$formatted : $formatted;
2843
- }
2844
- $attributes .= $this->_createParams( $theExdate['params'] );
2845
- $output .= $this->_createElement( 'EXDATE', $attributes, $content );
2846
- }
2847
- return $output;
2848
- }
2849
- /**
2850
- * set calendar component property exdate
2851
- *
2852
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2853
- * @since 2.5.1 - 2008-11-05
2854
- * @param array exdates
2855
- * @param array $params, optional
2856
- * @param integer $index, optional
2857
- * @return bool
2858
- */
2859
- function setExdate( $exdates, $params=FALSE, $index=FALSE ) {
2860
- if( empty( $exdates )) {
2861
- if( $this->getConfig( 'allowEmpty' )) {
2862
- iCalUtilityFunctions::_setMval( $this->exdate, null, $params, FALSE, $index );
2863
- return TRUE;
2864
- }
2865
- else
2866
- return FALSE;
2867
- }
2868
- $input = array( 'params' => iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' )));
2869
- /* ev. check 1:st date and save ev. timezone **/
2870
- iCalUtilityFunctions::_chkdatecfg( reset( $exdates ), $parno, $input['params'] );
2871
- iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default parameter
2872
- foreach( $exdates as $eix => $theExdate ) {
2873
- if( iCalUtilityFunctions::_isArrayTimestampDate( $theExdate ))
2874
- $exdatea = iCalUtilityFunctions::_timestamp2date( $theExdate, $parno );
2875
- elseif( is_array( $theExdate ))
2876
- $exdatea = iCalUtilityFunctions::_date_time_array( $theExdate, $parno );
2877
- elseif( 8 <= strlen( trim( $theExdate ))) // ex. 2006-08-03 10:12:18
2878
- $exdatea = iCalUtilityFunctions::_date_time_string( $theExdate, $parno );
2879
- if( 3 == $parno )
2880
- unset( $exdatea['hour'], $exdatea['min'], $exdatea['sec'], $exdatea['tz'] );
2881
- elseif( isset( $exdatea['tz'] ))
2882
- $exdatea['tz'] = (string) $exdatea['tz'];
2883
- if( isset( $input['params']['TZID'] ) ||
2884
- ( isset( $exdatea['tz'] ) && !iCalUtilityFunctions::_isOffset( $exdatea['tz'] )) ||
2885
- ( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] ))) ||
2886
- ( isset( $input['value'][0]['tz'] ) && !iCalUtilityFunctions::_isOffset( $input['value'][0]['tz'] )))
2887
- unset( $exdatea['tz'] );
2888
- $input['value'][] = $exdatea;
2889
- }
2890
- if( 0 >= count( $input['value'] ))
2891
- return FALSE;
2892
- if( 3 == $parno ) {
2893
- $input['params']['VALUE'] = 'DATE';
2894
- unset( $input['params']['TZID'] );
2895
- }
2896
- iCalUtilityFunctions::_setMval( $this->exdate, $input['value'], $input['params'], FALSE, $index );
2897
- return TRUE;
2898
- }
2899
- /*********************************************************************************/
2900
- /**
2901
- * Property Name: EXRULE
2902
- */
2903
- /**
2904
- * creates formatted output for calendar component property exrule
2905
- *
2906
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2907
- * @since 2.4.8 - 2008-10-22
2908
- * @return string
2909
- */
2910
- function createExrule() {
2911
- if( empty( $this->exrule )) return FALSE;
2912
- return $this->_format_recur( 'EXRULE', $this->exrule );
2913
- }
2914
- /**
2915
- * set calendar component property exdate
2916
- *
2917
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2918
- * @since 2.5.1 - 2008-11-05
2919
- * @param array $exruleset
2920
- * @param array $params, optional
2921
- * @param integer $index, optional
2922
- * @return bool
2923
- */
2924
- function setExrule( $exruleset, $params=FALSE, $index=FALSE ) {
2925
- if( empty( $exruleset )) if( $this->getConfig( 'allowEmpty' )) $exruleset = null; else return FALSE;
2926
- iCalUtilityFunctions::_setMval( $this->exrule, iCalUtilityFunctions::_setRexrule( $exruleset ), $params, FALSE, $index );
2927
- return TRUE;
2928
- }
2929
- /*********************************************************************************/
2930
- /**
2931
- * Property Name: FREEBUSY
2932
- */
2933
- /**
2934
- * creates formatted output for calendar component property freebusy
2935
- *
2936
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2937
- * @since 2.4.8 - 2008-10-22
2938
- * @return string
2939
- */
2940
- function createFreebusy() {
2941
- if( empty( $this->freebusy )) return FALSE;
2942
- $output = null;
2943
- foreach( $this->freebusy as $freebusyPart ) {
2944
- if( empty( $freebusyPart['value'] )) {
2945
- if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'FREEBUSY' );
2946
- continue;
2947
- }
2948
- $attributes = $content = null;
2949
- if( isset( $freebusyPart['value']['fbtype'] )) {
2950
- $attributes .= $this->intAttrDelimiter.'FBTYPE='.$freebusyPart['value']['fbtype'];
2951
- unset( $freebusyPart['value']['fbtype'] );
2952
- $freebusyPart['value'] = array_values( $freebusyPart['value'] );
2953
- }
2954
- else
2955
- $attributes .= $this->intAttrDelimiter.'FBTYPE=BUSY';
2956
- $attributes .= $this->_createParams( $freebusyPart['params'] );
2957
- $fno = 1;
2958
- $cnt = count( $freebusyPart['value']);
2959
- foreach( $freebusyPart['value'] as $periodix => $freebusyPeriod ) {
2960
- $formatted = iCalUtilityFunctions::_format_date_time( $freebusyPeriod[0] );
2961
- $content .= $formatted;
2962
- $content .= '/';
2963
- $cnt2 = count( $freebusyPeriod[1]);
2964
- if( array_key_exists( 'year', $freebusyPeriod[1] )) // date-time
2965
- $cnt2 = 7;
2966
- elseif( array_key_exists( 'week', $freebusyPeriod[1] )) // duration
2967
- $cnt2 = 5;
2968
- if(( 7 == $cnt2 ) && // period= -> date-time
2969
- isset( $freebusyPeriod[1]['year'] ) &&
2970
- isset( $freebusyPeriod[1]['month'] ) &&
2971
- isset( $freebusyPeriod[1]['day'] )) {
2972
- $content .= iCalUtilityFunctions::_format_date_time( $freebusyPeriod[1] );
2973
- }
2974
- else { // period= -> dur-time
2975
- $content .= iCalUtilityFunctions::_format_duration( $freebusyPeriod[1] );
2976
- }
2977
- if( $fno < $cnt )
2978
- $content .= ',';
2979
- $fno++;
2980
- }
2981
- $output .= $this->_createElement( 'FREEBUSY', $attributes, $content );
2982
- }
2983
- return $output;
2984
- }
2985
- /**
2986
- * set calendar component property freebusy
2987
- *
2988
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2989
- * @since 2.8.10 - 2011-03-24
2990
- * @param string $fbType
2991
- * @param array $fbValues
2992
- * @param array $params, optional
2993
- * @param integer $index, optional
2994
- * @return bool
2995
- */
2996
- function setFreebusy( $fbType, $fbValues, $params=FALSE, $index=FALSE ) {
2997
- if( empty( $fbValues )) {
2998
- if( $this->getConfig( 'allowEmpty' )) {
2999
- iCalUtilityFunctions::_setMval( $this->freebusy, null, $params, FALSE, $index );
3000
- return TRUE;
3001
- }
3002
- else
3003
- return FALSE;
3004
- }
3005
- $fbType = strtoupper( $fbType );
3006
- if(( !in_array( $fbType, array( 'FREE', 'BUSY', 'BUSY-UNAVAILABLE', 'BUSY-TENTATIVE' ))) &&
3007
- ( 'X-' != substr( $fbType, 0, 2 )))
3008
- $fbType = 'BUSY';
3009
- $input = array( 'fbtype' => $fbType );
3010
- foreach( $fbValues as $fbPeriod ) { // periods => period
3011
- if( empty( $fbPeriod ))
3012
- continue;
3013
- $freebusyPeriod = array();
3014
- foreach( $fbPeriod as $fbMember ) { // pairs => singlepart
3015
- $freebusyPairMember = array();
3016
- if( is_array( $fbMember )) {
3017
- if( iCalUtilityFunctions::_isArrayDate( $fbMember )) { // date-time value
3018
- $freebusyPairMember = iCalUtilityFunctions::_date_time_array( $fbMember, 7 );
3019
- $freebusyPairMember['tz'] = 'Z';
3020
- }
3021
- elseif( iCalUtilityFunctions::_isArrayTimestampDate( $fbMember )) { // timestamp value
3022
- $freebusyPairMember = iCalUtilityFunctions::_timestamp2date( $fbMember['timestamp'], 7 );
3023
- $freebusyPairMember['tz'] = 'Z';
3024
- }
3025
- else { // array format duration
3026
- $freebusyPairMember = iCalUtilityFunctions::_duration_array( $fbMember );
3027
- }
3028
- }
3029
- elseif(( 3 <= strlen( trim( $fbMember ))) && // string format duration
3030
- ( in_array( $fbMember{0}, array( 'P', '+', '-' )))) {
3031
- if( 'P' != $fbMember{0} )
3032
- $fbmember = substr( $fbMember, 1 );
3033
- $freebusyPairMember = iCalUtilityFunctions::_duration_string( $fbMember );
3034
- }
3035
- elseif( 8 <= strlen( trim( $fbMember ))) { // text date ex. 2006-08-03 10:12:18
3036
- $freebusyPairMember = iCalUtilityFunctions::_date_time_string( $fbMember, 7 );
3037
- $freebusyPairMember['tz'] = 'Z';
3038
- }
3039
- $freebusyPeriod[] = $freebusyPairMember;
3040
- }
3041
- $input[] = $freebusyPeriod;
3042
- }
3043
- iCalUtilityFunctions::_setMval( $this->freebusy, $input, $params, FALSE, $index );
3044
- return TRUE;
3045
- }
3046
- /*********************************************************************************/
3047
- /**
3048
- * Property Name: GEO
3049
- */
3050
- /**
3051
- * creates formatted output for calendar component property geo
3052
- *
3053
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3054
- * @since 2.4.8 - 2008-10-21
3055
- * @return string
3056
- */
3057
- function createGeo() {
3058
- if( empty( $this->geo )) return FALSE;
3059
- if( empty( $this->geo['value'] ))
3060
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'GEO' ) : FALSE;
3061
- $attributes = $this->_createParams( $this->geo['params'] );
3062
- $content = null;
3063
- $content .= number_format( (float) $this->geo['value']['latitude'], 6, '.', '');
3064
- $content .= ';';
3065
- $content .= number_format( (float) $this->geo['value']['longitude'], 6, '.', '');
3066
- return $this->_createElement( 'GEO', $attributes, $content );
3067
- }
3068
- /**
3069
- * set calendar component property geo
3070
- *
3071
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3072
- * @since 2.4.8 - 2008-11-04
3073
- * @param float $latitude
3074
- * @param float $longitude
3075
- * @param array $params optional
3076
- * @return bool
3077
- */
3078
- function setGeo( $latitude, $longitude, $params=FALSE ) {
3079
- if( !empty( $latitude ) && !empty( $longitude )) {
3080
- if( !is_array( $this->geo )) $this->geo = array();
3081
- $this->geo['value']['latitude'] = $latitude;
3082
- $this->geo['value']['longitude'] = $longitude;
3083
- $this->geo['params'] = iCalUtilityFunctions::_setParams( $params );
3084
- }
3085
- elseif( $this->getConfig( 'allowEmpty' ))
3086
- $this->geo = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params ) );
3087
- else
3088
- return FALSE;
3089
- return TRUE;
3090
- }
3091
- /*********************************************************************************/
3092
- /**
3093
- * Property Name: LAST-MODIFIED
3094
- */
3095
- /**
3096
- * creates formatted output for calendar component property last-modified
3097
- *
3098
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3099
- * @since 2.4.8 - 2008-10-21
3100
- * @return string
3101
- */
3102
- function createLastModified() {
3103
- if( empty( $this->lastmodified )) return FALSE;
3104
- $attributes = $this->_createParams( $this->lastmodified['params'] );
3105
- $formatted = iCalUtilityFunctions::_format_date_time( $this->lastmodified['value'], 7 );
3106
- return $this->_createElement( 'LAST-MODIFIED', $attributes, $formatted );
3107
- }
3108
- /**
3109
- * set calendar component property completed
3110
- *
3111
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3112
- * @since 2.4.8 - 2008-10-23
3113
- * @param mixed $year optional
3114
- * @param mixed $month optional
3115
- * @param int $day optional
3116
- * @param int $hour optional
3117
- * @param int $min optional
3118
- * @param int $sec optional
3119
- * @param array $params optional
3120
- * @return boll
3121
- */
3122
- function setLastModified( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
3123
- if( empty( $year ))
3124
- $year = date('Ymd\THis', mktime( date( 'H' ), date( 'i' ), date( 's' ) - date( 'Z'), date( 'm' ), date( 'd' ), date( 'Y' )));
3125
- $this->lastmodified = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
3126
- return TRUE;
3127
- }
3128
- /*********************************************************************************/
3129
- /**
3130
- * Property Name: LOCATION
3131
- */
3132
- /**
3133
- * creates formatted output for calendar component property location
3134
- *
3135
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3136
- * @since 2.4.8 - 2008-10-22
3137
- * @return string
3138
- */
3139
- function createLocation() {
3140
- if( empty( $this->location )) return FALSE;
3141
- if( empty( $this->location['value'] ))
3142
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'LOCATION' ) : FALSE;
3143
- $attributes = $this->_createParams( $this->location['params'], array( 'ALTREP', 'LANGUAGE' ));
3144
- $content = $this->_strrep( $this->location['value'] );
3145
- return $this->_createElement( 'LOCATION', $attributes, $content );
3146
- }
3147
- /**
3148
- * set calendar component property location
3149
- '
3150
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3151
- * @since 2.4.8 - 2008-11-04
3152
- * @param string $value
3153
- * @param array params optional
3154
- * @return bool
3155
- */
3156
- function setLocation( $value, $params=FALSE ) {
3157
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
3158
- $this->location = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
3159
- return TRUE;
3160
- }
3161
- /*********************************************************************************/
3162
- /**
3163
- * Property Name: ORGANIZER
3164
- */
3165
- /**
3166
- * creates formatted output for calendar component property organizer
3167
- *
3168
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3169
- * @since 2.6.33 - 2010-12-17
3170
- * @return string
3171
- */
3172
- function createOrganizer() {
3173
- if( empty( $this->organizer )) return FALSE;
3174
- if( empty( $this->organizer['value'] ))
3175
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'ORGANIZER' ) : FALSE;
3176
- $attributes = $this->_createParams( $this->organizer['params']
3177
- , array( 'CN', 'DIR', 'SENT-BY', 'LANGUAGE' ));
3178
- return $this->_createElement( 'ORGANIZER', $attributes, $this->organizer['value'] );
3179
- }
3180
- /**
3181
- * set calendar component property organizer
3182
- *
3183
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3184
- * @since 2.6.27 - 2010-11-29
3185
- * @param string $value
3186
- * @param array params optional
3187
- * @return bool
3188
- */
3189
- function setOrganizer( $value, $params=FALSE ) {
3190
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
3191
- if( FALSE === ( $pos = strpos( substr( $value, 0, 9 ), ':' )))
3192
- $value = 'MAILTO:'.$value;
3193
- else
3194
- $value = strtolower( substr( $value, 0, $pos )).substr( $value, $pos );
3195
- $value = str_replace( 'mailto:', 'MAILTO:', $value );
3196
- $this->organizer = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
3197
- if( isset( $this->organizer['params']['SENT-BY'] )){
3198
- if( 'mailto:' !== strtolower( substr( $this->organizer['params']['SENT-BY'], 0, 7 )))
3199
- $this->organizer['params']['SENT-BY'] = 'MAILTO:'.$this->organizer['params']['SENT-BY'];
3200
- else
3201
- $this->organizer['params']['SENT-BY'] = 'MAILTO:'.substr( $this->organizer['params']['SENT-BY'], 7 );
3202
- }
3203
- return TRUE;
3204
- }
3205
- /*********************************************************************************/
3206
- /**
3207
- * Property Name: PERCENT-COMPLETE
3208
- */
3209
- /**
3210
- * creates formatted output for calendar component property percent-complete
3211
- *
3212
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3213
- * @since 2.9.3 - 2011-05-14
3214
- * @return string
3215
- */
3216
- function createPercentComplete() {
3217
- if( !isset($this->percentcomplete) || ( empty( $this->percentcomplete ) && !is_numeric( $this->percentcomplete ))) return FALSE;
3218
- if( !isset( $this->percentcomplete['value'] ) || ( empty( $this->percentcomplete['value'] ) && !is_numeric( $this->percentcomplete['value'] )))
3219
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'PERCENT-COMPLETE' ) : FALSE;
3220
- $attributes = $this->_createParams( $this->percentcomplete['params'] );
3221
- return $this->_createElement( 'PERCENT-COMPLETE', $attributes, $this->percentcomplete['value'] );
3222
- }
3223
- /**
3224
- * set calendar component property percent-complete
3225
- *
3226
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3227
- * @since 2.9.3 - 2011-05-14
3228
- * @param int $value
3229
- * @param array $params optional
3230
- * @return bool
3231
- */
3232
- function setPercentComplete( $value, $params=FALSE ) {
3233
- if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
3234
- $this->percentcomplete = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
3235
- return TRUE;
3236
- }
3237
- /*********************************************************************************/
3238
- /**
3239
- * Property Name: PRIORITY
3240
- */
3241
- /**
3242
- * creates formatted output for calendar component property priority
3243
- *
3244
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3245
- * @since 2.9.3 - 2011-05-14
3246
- * @return string
3247
- */
3248
- function createPriority() {
3249
- if( !isset($this->priority) || ( empty( $this->priority ) && !is_numeric( $this->priority ))) return FALSE;
3250
- if( !isset( $this->priority['value'] ) || ( empty( $this->priority['value'] ) && !is_numeric( $this->priority['value'] )))
3251
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'PRIORITY' ) : FALSE;
3252
- $attributes = $this->_createParams( $this->priority['params'] );
3253
- return $this->_createElement( 'PRIORITY', $attributes, $this->priority['value'] );
3254
- }
3255
- /**
3256
- * set calendar component property priority
3257
- *
3258
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3259
- * @since 2.9.3 - 2011-05-14
3260
- * @param int $value
3261
- * @param array $params optional
3262
- * @return bool
3263
- */
3264
- function setPriority( $value, $params=FALSE ) {
3265
- if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
3266
- $this->priority = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
3267
- return TRUE;
3268
- }
3269
- /*********************************************************************************/
3270
- /**
3271
- * Property Name: RDATE
3272
- */
3273
- /**
3274
- * creates formatted output for calendar component property rdate
3275
- *
3276
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3277
- * @since 2.4.16 - 2008-10-26
3278
- * @return string
3279
- */
3280
- function createRdate() {
3281
- if( empty( $this->rdate )) return FALSE;
3282
- $utctime = ( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) ? TRUE : FALSE;
3283
- $output = null;
3284
- if( $utctime )
3285
- unset( $this->rdate['params']['TZID'] );
3286
- foreach( $this->rdate as $theRdate ) {
3287
- if( empty( $theRdate['value'] )) {
3288
- if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RDATE' );
3289
- continue;
3290
- }
3291
- if( $utctime )
3292
- unset( $theRdate['params']['TZID'] );
3293
- $attributes = $this->_createParams( $theRdate['params'] );
3294
- $cnt = count( $theRdate['value'] );
3295
- $content = null;
3296
- $rno = 1;
3297
- foreach( $theRdate['value'] as $rpix => $rdatePart ) {
3298
- $contentPart = null;
3299
- if( is_array( $rdatePart ) &&
3300
- isset( $theRdate['params']['VALUE'] ) && ( 'PERIOD' == $theRdate['params']['VALUE'] )) { // PERIOD
3301
- if( $utctime )
3302
- unset( $rdatePart[0]['tz'] );
3303
- $formatted = iCalUtilityFunctions::_format_date_time( $rdatePart[0]); // PERIOD part 1
3304
- if( $utctime || !empty( $theRdate['params']['TZID'] ))
3305
- $formatted = str_replace( 'Z', '', $formatted);
3306
- if( 0 < $rpix ) {
3307
- if( !empty( $rdatePart[0]['tz'] ) && iCalUtilityFunctions::_isOffset( $rdatePart[0]['tz'] )) {
3308
- if( 'Z' != substr( $formatted, -1 )) $formatted .= 'Z';
3309
- }
3310
- else
3311
- $formatted = str_replace( 'Z', '', $formatted );
3312
- }
3313
- $contentPart .= $formatted;
3314
- $contentPart .= '/';
3315
- $cnt2 = count( $rdatePart[1]);
3316
- if( array_key_exists( 'year', $rdatePart[1] )) {
3317
- if( array_key_exists( 'hour', $rdatePart[1] ))
3318
- $cnt2 = 7; // date-time
3319
- else
3320
- $cnt2 = 3; // date
3321
- }
3322
- elseif( array_key_exists( 'week', $rdatePart[1] )) // duration
3323
- $cnt2 = 5;
3324
- if(( 7 == $cnt2 ) && // period= -> date-time
3325
- isset( $rdatePart[1]['year'] ) &&
3326
- isset( $rdatePart[1]['month'] ) &&
3327
- isset( $rdatePart[1]['day'] )) {
3328
- if( $utctime )
3329
- unset( $rdatePart[1]['tz'] );
3330
- $formatted = iCalUtilityFunctions::_format_date_time( $rdatePart[1] ); // PERIOD part 2
3331
- if( $utctime || !empty( $theRdate['params']['TZID'] ))
3332
- $formatted = str_replace( 'Z', '', $formatted);
3333
- if( !empty( $rdatePart[0]['tz'] ) && iCalUtilityFunctions::_isOffset( $rdatePart[0]['tz'] )) {
3334
- if( 'Z' != substr( $formatted, -1 )) $formatted .= 'Z';
3335
- }
3336
- else
3337
- $formatted = str_replace( 'Z', '', $formatted );
3338
- $contentPart .= $formatted;
3339
- }
3340
- else { // period= -> dur-time
3341
- $contentPart .= iCalUtilityFunctions::_format_duration( $rdatePart[1] );
3342
- }
3343
- } // PERIOD end
3344
- else { // SINGLE date start
3345
- if( $utctime )
3346
- unset( $rdatePart['tz'] );
3347
- $formatted = iCalUtilityFunctions::_format_date_time( $rdatePart);
3348
- if( $utctime || !empty( $theRdate['params']['TZID'] ))
3349
- $formatted = str_replace( 'Z', '', $formatted);
3350
- if( !$utctime && ( 0 < $rpix )) {
3351
- if( !empty( $theRdate['value'][0]['tz'] ) && iCalUtilityFunctions::_isOffset( $theRdate['value'][0]['tz'] )) {
3352
- if( 'Z' != substr( $formatted, -1 ))
3353
- $formatted .= 'Z';
3354
- }
3355
- else
3356
- $formatted = str_replace( 'Z', '', $formatted );
3357
- }
3358
- $contentPart .= $formatted;
3359
- }
3360
- $content .= $contentPart;
3361
- if( $rno < $cnt )
3362
- $content .= ',';
3363
- $rno++;
3364
- }
3365
- $output .= $this->_createElement( 'RDATE', $attributes, $content );
3366
- }
3367
- return $output;
3368
- }
3369
- /**
3370
- * set calendar component property rdate
3371
- *
3372
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3373
- * @since 2.5.1 - 2008-11-07
3374
- * @param array $rdates
3375
- * @param array $params, optional
3376
- * @param integer $index, optional
3377
- * @return bool
3378
- */
3379
- function setRdate( $rdates, $params=FALSE, $index=FALSE ) {
3380
- if( empty( $rdates )) {
3381
- if( $this->getConfig( 'allowEmpty' )) {
3382
- iCalUtilityFunctions::_setMval( $this->rdate, null, $params, FALSE, $index );
3383
- return TRUE;
3384
- }
3385
- else
3386
- return FALSE;
3387
- }
3388
- $input = array( 'params' => iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' )));
3389
- if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) {
3390
- unset( $input['params']['TZID'] );
3391
- $input['params']['VALUE'] = 'DATE-TIME';
3392
- }
3393
- /* check if PERIOD, if not set */
3394
- if((!isset( $input['params']['VALUE'] ) || !in_array( $input['params']['VALUE'], array( 'DATE', 'PERIOD' ))) &&
3395
- isset( $rdates[0] ) && is_array( $rdates[0] ) && ( 2 == count( $rdates[0] )) &&
3396
- isset( $rdates[0][0] ) && isset( $rdates[0][1] ) && !isset( $rdates[0]['timestamp'] ) &&
3397
- (( is_array( $rdates[0][0] ) && ( isset( $rdates[0][0]['timestamp'] ) ||
3398
- iCalUtilityFunctions::_isArrayDate( $rdates[0][0] ))) ||
3399
- ( is_string( $rdates[0][0] ) && ( 8 <= strlen( trim( $rdates[0][0] ))))) &&
3400
- ( is_array( $rdates[0][1] ) || ( is_string( $rdates[0][1] ) && ( 3 <= strlen( trim( $rdates[0][1] ))))))
3401
- $input['params']['VALUE'] = 'PERIOD';
3402
- /* check 1:st date, upd. $parno (opt) and save ev. timezone **/
3403
- $date = reset( $rdates );
3404
- if( isset( $input['params']['VALUE'] ) && ( 'PERIOD' == $input['params']['VALUE'] )) // PERIOD
3405
- $date = reset( $date );
3406
- iCalUtilityFunctions::_chkdatecfg( $date, $parno, $input['params'] );
3407
- if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' )))
3408
- unset( $input['params']['TZID'] );
3409
- iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default
3410
- foreach( $rdates as $rpix => $theRdate ) {
3411
- $inputa = null;
3412
- if( is_array( $theRdate )) {
3413
- if( isset( $input['params']['VALUE'] ) && ( 'PERIOD' == $input['params']['VALUE'] )) { // PERIOD
3414
- foreach( $theRdate as $rix => $rPeriod ) {
3415
- if( is_array( $rPeriod )) {
3416
- if( iCalUtilityFunctions::_isArrayTimestampDate( $rPeriod )) // timestamp
3417
- $inputab = ( isset( $rPeriod['tz'] )) ? iCalUtilityFunctions::_timestamp2date( $rPeriod, $parno ) : iCalUtilityFunctions::_timestamp2date( $rPeriod, 6 );
3418
- elseif( iCalUtilityFunctions::_isArrayDate( $rPeriod ))
3419
- $inputab = ( 3 < count ( $rPeriod )) ? iCalUtilityFunctions::_date_time_array( $rPeriod, $parno ) : iCalUtilityFunctions::_date_time_array( $rPeriod, 6 );
3420
- elseif (( 1 == count( $rPeriod )) && ( 8 <= strlen( reset( $rPeriod )))) // text-date
3421
- $inputab = iCalUtilityFunctions::_date_time_string( reset( $rPeriod ), $parno );
3422
- else // array format duration
3423
- $inputab = iCalUtilityFunctions::_duration_array( $rPeriod );
3424
- }
3425
- elseif(( 3 <= strlen( trim( $rPeriod ))) && // string format duration
3426
- ( in_array( $rPeriod[0], array( 'P', '+', '-' )))) {
3427
- if( 'P' != $rPeriod[0] )
3428
- $rPeriod = substr( $rPeriod, 1 );
3429
- $inputab = iCalUtilityFunctions::_duration_string( $rPeriod );
3430
- }
3431
- elseif( 8 <= strlen( trim( $rPeriod ))) // text date ex. 2006-08-03 10:12:18
3432
- $inputab = iCalUtilityFunctions::_date_time_string( $rPeriod, $parno );
3433
- if( isset( $input['params']['TZID'] ) ||
3434
- ( isset( $inputab['tz'] ) && !iCalUtilityFunctions::_isOffset( $inputab['tz'] )) ||
3435
- ( isset( $inputa[0] ) && ( !isset( $inputa[0]['tz'] ))) ||
3436
- ( isset( $inputa[0]['tz'] ) && !iCalUtilityFunctions::_isOffset( $inputa[0]['tz'] )))
3437
- unset( $inputab['tz'] );
3438
- $inputa[] = $inputab;
3439
- }
3440
- } // PERIOD end
3441
- elseif ( iCalUtilityFunctions::_isArrayTimestampDate( $theRdate )) // timestamp
3442
- $inputa = iCalUtilityFunctions::_timestamp2date( $theRdate, $parno );
3443
- else // date[-time]
3444
- $inputa = iCalUtilityFunctions::_date_time_array( $theRdate, $parno );
3445
- }
3446
- elseif( 8 <= strlen( trim( $theRdate ))) // text date ex. 2006-08-03 10:12:18
3447
- $inputa = iCalUtilityFunctions::_date_time_string( $theRdate, $parno );
3448
- if( !isset( $input['params']['VALUE'] ) || ( 'PERIOD' != $input['params']['VALUE'] )) { // no PERIOD
3449
- if( 3 == $parno )
3450
- unset( $inputa['hour'], $inputa['min'], $inputa['sec'], $inputa['tz'] );
3451
- elseif( isset( $inputa['tz'] ))
3452
- $inputa['tz'] = (string) $inputa['tz'];
3453
- if( isset( $input['params']['TZID'] ) ||
3454
- ( isset( $inputa['tz'] ) && !iCalUtilityFunctions::_isOffset( $inputa['tz'] )) ||
3455
- ( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] ))) ||
3456
- ( isset( $input['value'][0]['tz'] ) && !iCalUtilityFunctions::_isOffset( $input['value'][0]['tz'] )))
3457
- unset( $inputa['tz'] );
3458
- }
3459
- $input['value'][] = $inputa;
3460
- }
3461
- if( 3 == $parno ) {
3462
- $input['params']['VALUE'] = 'DATE';
3463
- unset( $input['params']['TZID'] );
3464
- }
3465
- iCalUtilityFunctions::_setMval( $this->rdate, $input['value'], $input['params'], FALSE, $index );
3466
- return TRUE;
3467
- }
3468
- /*********************************************************************************/
3469
- /**
3470
- * Property Name: RECURRENCE-ID
3471
- */
3472
- /**
3473
- * creates formatted output for calendar component property recurrence-id
3474
- *
3475
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3476
- * @since 2.9.6 - 2011-05-15
3477
- * @return string
3478
- */
3479
- function createRecurrenceid() {
3480
- if( empty( $this->recurrenceid )) return FALSE;
3481
- if( empty( $this->recurrenceid['value'] ))
3482
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'RECURRENCE-ID' ) : FALSE;
3483
- $formatted = iCalUtilityFunctions::_format_date_time( $this->recurrenceid['value'] );
3484
- if(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
3485
- ( !isset( $this->recurrenceid['params']['VALUE'] ) || ( $this->recurrenceid['params']['VALUE'] != 'DATE' )) &&
3486
- !isset( $this->recurrenceid['params']['TZID'] ))
3487
- $this->recurrenceid['params']['TZID'] = $tzid;
3488
- $attributes = $this->_createParams( $this->recurrenceid['params'] );
3489
- return $this->_createElement( 'RECURRENCE-ID', $attributes, $formatted );
3490
- }
3491
- /**
3492
- * set calendar component property recurrence-id
3493
- *
3494
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3495
- * @since 2.9.6 - 2011-05-15
3496
- * @param mixed $year
3497
- * @param mixed $month optional
3498
- * @param int $day optional
3499
- * @param int $hour optional
3500
- * @param int $min optional
3501
- * @param int $sec optional
3502
- * @param array $params optional
3503
- * @return bool
3504
- */
3505
- function setRecurrenceid( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
3506
- if( empty( $year )) {
3507
- if( $this->getConfig( 'allowEmpty' )) {
3508
- $this->recurrenceid = array( 'value' => null, 'params' => null );
3509
- return TRUE;
3510
- }
3511
- else
3512
- return FALSE;
3513
- }
3514
- $this->recurrenceid = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig( 'TZID' ));
3515
- return TRUE;
3516
- }
3517
- /*********************************************************************************/
3518
- /**
3519
- * Property Name: RELATED-TO
3520
- */
3521
- /**
3522
- * creates formatted output for calendar component property related-to
3523
- *
3524
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3525
- * @since 2.4.8 - 2008-10-23
3526
- * @return string
3527
- */
3528
- function createRelatedTo() {
3529
- if( empty( $this->relatedto )) return FALSE;
3530
- $output = null;
3531
- foreach( $this->relatedto as $relation ) {
3532
- if( empty( $relation['value'] )) {
3533
- if( $this->getConfig( 'allowEmpty' )) $output.= $this->_createElement( 'RELATED-TO', $this->_createParams( $relation['params'] ));
3534
- continue;
3535
- }
3536
- $attributes = $this->_createParams( $relation['params'] );
3537
- $content = ( 'xcal' != $this->format ) ? '<' : '';
3538
- $content .= $this->_strrep( $relation['value'] );
3539
- $content .= ( 'xcal' != $this->format ) ? '>' : '';
3540
- $output .= $this->_createElement( 'RELATED-TO', $attributes, $content );
3541
- }
3542
- return $output;
3543
- }
3544
- /**
3545
- * set calendar component property related-to
3546
- *
3547
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3548
- * @since 2.5.1 - 2008-11-07
3549
- * @param float $relid
3550
- * @param array $params, optional
3551
- * @param index $index, optional
3552
- * @return bool
3553
- */
3554
- function setRelatedTo( $value, $params=FALSE, $index=FALSE ) {
3555
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
3556
- if(( '<' == substr( $value, 0, 1 )) && ( '>' == substr( $value, -1 )))
3557
- $value = substr( $value, 1, ( strlen( $value ) - 2 ));
3558
- iCalUtilityFunctions::_existRem( $params, 'RELTYPE', 'PARENT', TRUE ); // remove default
3559
- iCalUtilityFunctions::_setMval( $this->relatedto, $value, $params, FALSE, $index );
3560
- return TRUE;
3561
- }
3562
- /*********************************************************************************/
3563
- /**
3564
- * Property Name: REPEAT
3565
- */
3566
- /**
3567
- * creates formatted output for calendar component property repeat
3568
- *
3569
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3570
- * @since 2.9.3 - 2011-05-14
3571
- * @return string
3572
- */
3573
- function createRepeat() {
3574
- if( !isset( $this->repeat ) || ( empty( $this->repeat ) && !is_numeric( $this->repeat ))) return FALSE;
3575
- if( !isset( $this->repeat['value']) || ( empty( $this->repeat['value'] ) && !is_numeric( $this->repeat['value'] )))
3576
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'REPEAT' ) : FALSE;
3577
- $attributes = $this->_createParams( $this->repeat['params'] );
3578
- return $this->_createElement( 'REPEAT', $attributes, $this->repeat['value'] );
3579
- }
3580
- /**
3581
- * set calendar component property transp
3582
- *
3583
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3584
- * @since 2.9.3 - 2011-05-14
3585
- * @param string $value
3586
- * @param array $params optional
3587
- * @return void
3588
- */
3589
- function setRepeat( $value, $params=FALSE ) {
3590
- if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
3591
- $this->repeat = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
3592
- return TRUE;
3593
- }
3594
- /*********************************************************************************/
3595
- /**
3596
- * Property Name: REQUEST-STATUS
3597
- */
3598
- /**
3599
- * creates formatted output for calendar component property request-status
3600
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3601
- * @since 2.4.8 - 2008-10-23
3602
- * @return string
3603
- */
3604
- function createRequestStatus() {
3605
- if( empty( $this->requeststatus )) return FALSE;
3606
- $output = null;
3607
- foreach( $this->requeststatus as $rstat ) {
3608
- if( empty( $rstat['value']['statcode'] )) {
3609
- if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'REQUEST-STATUS' );
3610
- continue;
3611
- }
3612
- $attributes = $this->_createParams( $rstat['params'], array( 'LANGUAGE' ));
3613
- $content = number_format( (float) $rstat['value']['statcode'], 2, '.', '');
3614
- $content .= ';'.$this->_strrep( $rstat['value']['text'] );
3615
- if( isset( $rstat['value']['extdata'] ))
3616
- $content .= ';'.$this->_strrep( $rstat['value']['extdata'] );
3617
- $output .= $this->_createElement( 'REQUEST-STATUS', $attributes, $content );
3618
- }
3619
- return $output;
3620
- }
3621
- /**
3622
- * set calendar component property request-status
3623
- *
3624
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3625
- * @since 2.5.1 - 2008-11-05
3626
- * @param float $statcode
3627
- * @param string $text
3628
- * @param string $extdata, optional
3629
- * @param array $params, optional
3630
- * @param integer $index, optional
3631
- * @return bool
3632
- */
3633
- function setRequestStatus( $statcode, $text, $extdata=FALSE, $params=FALSE, $index=FALSE ) {
3634
- if( empty( $statcode ) || empty( $text )) if( $this->getConfig( 'allowEmpty' )) $statcode = $text = null; else return FALSE;
3635
- $input = array( 'statcode' => $statcode, 'text' => $text );
3636
- if( $extdata )
3637
- $input['extdata'] = $extdata;
3638
- iCalUtilityFunctions::_setMval( $this->requeststatus, $input, $params, FALSE, $index );
3639
- return TRUE;
3640
- }
3641
- /*********************************************************************************/
3642
- /**
3643
- * Property Name: RESOURCES
3644
- */
3645
- /**
3646
- * creates formatted output for calendar component property resources
3647
- *
3648
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3649
- * @since 2.4.8 - 2008-10-23
3650
- * @return string
3651
- */
3652
- function createResources() {
3653
- if( empty( $this->resources )) return FALSE;
3654
- $output = null;
3655
- foreach( $this->resources as $resource ) {
3656
- if( empty( $resource['value'] )) {
3657
- if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RESOURCES' );
3658
- continue;
3659
- }
3660
- $attributes = $this->_createParams( $resource['params'], array( 'ALTREP', 'LANGUAGE' ));
3661
- if( is_array( $resource['value'] )) {
3662
- foreach( $resource['value'] as $rix => $resourcePart )
3663
- $resource['value'][$rix] = $this->_strrep( $resourcePart );
3664
- $content = implode( ',', $resource['value'] );
3665
- }
3666
- else
3667
- $content = $this->_strrep( $resource['value'] );
3668
- $output .= $this->_createElement( 'RESOURCES', $attributes, $content );
3669
- }
3670
- return $output;
3671
- }
3672
- /**
3673
- * set calendar component property recources
3674
- *
3675
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3676
- * @since 2.5.1 - 2008-11-05
3677
- * @param mixed $value
3678
- * @param array $params, optional
3679
- * @param integer $index, optional
3680
- * @return bool
3681
- */
3682
- function setResources( $value, $params=FALSE, $index=FALSE ) {
3683
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
3684
- iCalUtilityFunctions::_setMval( $this->resources, $value, $params, FALSE, $index );
3685
- return TRUE;
3686
- }
3687
- /*********************************************************************************/
3688
- /**
3689
- * Property Name: RRULE
3690
- */
3691
- /**
3692
- * creates formatted output for calendar component property rrule
3693
- *
3694
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3695
- * @since 2.4.8 - 2008-10-21
3696
- * @return string
3697
- */
3698
- function createRrule() {
3699
- if( empty( $this->rrule )) return FALSE;
3700
- return $this->_format_recur( 'RRULE', $this->rrule );
3701
- }
3702
- /**
3703
- * set calendar component property rrule
3704
- *
3705
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3706
- * @since 2.5.1 - 2008-11-05
3707
- * @param array $rruleset
3708
- * @param array $params, optional
3709
- * @param integer $index, optional
3710
- * @return void
3711
- */
3712
- function setRrule( $rruleset, $params=FALSE, $index=FALSE ) {
3713
- if( empty( $rruleset )) if( $this->getConfig( 'allowEmpty' )) $rruleset = null; else return FALSE;
3714
- iCalUtilityFunctions::_setMval( $this->rrule, iCalUtilityFunctions::_setRexrule( $rruleset ), $params, FALSE, $index );
3715
- return TRUE;
3716
- }
3717
- /*********************************************************************************/
3718
- /**
3719
- * Property Name: SEQUENCE
3720
- */
3721
- /**
3722
- * creates formatted output for calendar component property sequence
3723
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3724
- * @since 2.9.3 - 2011-05-14
3725
- * @return string
3726
- */
3727
- function createSequence() {
3728
- if( !isset( $this->sequence ) || ( empty( $this->sequence ) && !is_numeric( $this->sequence ))) return FALSE;
3729
- if(( !isset($this->sequence['value'] ) || ( empty( $this->sequence['value'] ) && !is_numeric( $this->sequence['value'] ))) &&
3730
- ( '0' != $this->sequence['value'] ))
3731
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SEQUENCE' ) : FALSE;
3732
- $attributes = $this->_createParams( $this->sequence['params'] );
3733
- return $this->_createElement( 'SEQUENCE', $attributes, $this->sequence['value'] );
3734
- }
3735
- /**
3736
- * set calendar component property sequence
3737
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3738
- * @since 2.9.3 - 2011-05-14
3739
- * @param int $value optional
3740
- * @param array $params optional
3741
- * @return bool
3742
- */
3743
- function setSequence( $value=FALSE, $params=FALSE ) {
3744
- if(( empty( $value ) && !is_numeric( $value )) && ( '0' != $value ))
3745
- $value = ( isset( $this->sequence['value'] ) && ( 0 < $this->sequence['value'] )) ? $this->sequence['value'] + 1 : 1;
3746
- $this->sequence = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
3747
- return TRUE;
3748
- }
3749
- /*********************************************************************************/
3750
- /**
3751
- * Property Name: STATUS
3752
- */
3753
- /**
3754
- * creates formatted output for calendar component property status
3755
- *
3756
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3757
- * @since 2.4.8 - 2008-10-21
3758
- * @return string
3759
- */
3760
- function createStatus() {
3761
- if( empty( $this->status )) return FALSE;
3762
- if( empty( $this->status['value'] ))
3763
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'STATUS' ) : FALSE;
3764
- $attributes = $this->_createParams( $this->status['params'] );
3765
- return $this->_createElement( 'STATUS', $attributes, $this->status['value'] );
3766
- }
3767
- /**
3768
- * set calendar component property status
3769
- *
3770
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3771
- * @since 2.4.8 - 2008-11-04
3772
- * @param string $value
3773
- * @param array $params optional
3774
- * @return bool
3775
- */
3776
- function setStatus( $value, $params=FALSE ) {
3777
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
3778
- $this->status = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
3779
- return TRUE;
3780
- }
3781
- /*********************************************************************************/
3782
- /**
3783
- * Property Name: SUMMARY
3784
- */
3785
- /**
3786
- * creates formatted output for calendar component property summary
3787
- *
3788
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3789
- * @since 2.4.8 - 2008-10-21
3790
- * @return string
3791
- */
3792
- function createSummary() {
3793
- if( empty( $this->summary )) return FALSE;
3794
- if( empty( $this->summary['value'] ))
3795
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SUMMARY' ) : FALSE;
3796
- $attributes = $this->_createParams( $this->summary['params'], array( 'ALTREP', 'LANGUAGE' ));
3797
- $content = $this->_strrep( $this->summary['value'] );
3798
- return $this->_createElement( 'SUMMARY', $attributes, $content );
3799
- }
3800
- /**
3801
- * set calendar component property summary
3802
- *
3803
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3804
- * @since 2.4.8 - 2008-11-04
3805
- * @param string $value
3806
- * @param string $params optional
3807
- * @return bool
3808
- */
3809
- function setSummary( $value, $params=FALSE ) {
3810
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
3811
- $this->summary = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
3812
- return TRUE;
3813
- }
3814
- /*********************************************************************************/
3815
- /**
3816
- * Property Name: TRANSP
3817
- */
3818
- /**
3819
- * creates formatted output for calendar component property transp
3820
- *
3821
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3822
- * @since 2.4.8 - 2008-10-21
3823
- * @return string
3824
- */
3825
- function createTransp() {
3826
- if( empty( $this->transp )) return FALSE;
3827
- if( empty( $this->transp['value'] ))
3828
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TRANSP' ) : FALSE;
3829
- $attributes = $this->_createParams( $this->transp['params'] );
3830
- return $this->_createElement( 'TRANSP', $attributes, $this->transp['value'] );
3831
- }
3832
- /**
3833
- * set calendar component property transp
3834
- *
3835
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3836
- * @since 2.4.8 - 2008-11-04
3837
- * @param string $value
3838
- * @param string $params optional
3839
- * @return bool
3840
- */
3841
- function setTransp( $value, $params=FALSE ) {
3842
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
3843
- $this->transp = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
3844
- return TRUE;
3845
- }
3846
- /*********************************************************************************/
3847
- /**
3848
- * Property Name: TRIGGER
3849
- */
3850
- /**
3851
- * creates formatted output for calendar component property trigger
3852
- *
3853
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3854
- * @since 2.4.16 - 2008-10-21
3855
- * @return string
3856
- */
3857
- function createTrigger() {
3858
- if( empty( $this->trigger )) return FALSE;
3859
- if( empty( $this->trigger['value'] ))
3860
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TRIGGER' ) : FALSE;
3861
- $content = $attributes = null;
3862
- if( isset( $this->trigger['value']['year'] ) &&
3863
- isset( $this->trigger['value']['month'] ) &&
3864
- isset( $this->trigger['value']['day'] ))
3865
- $content .= iCalUtilityFunctions::_format_date_time( $this->trigger['value'] );
3866
- else {
3867
- if( TRUE !== $this->trigger['value']['relatedStart'] )
3868
- $attributes .= $this->intAttrDelimiter.'RELATED=END';
3869
- if( $this->trigger['value']['before'] )
3870
- $content .= '-';
3871
- $content .= iCalUtilityFunctions::_format_duration( $this->trigger['value'] );
3872
- }
3873
- $attributes .= $this->_createParams( $this->trigger['params'] );
3874
- return $this->_createElement( 'TRIGGER', $attributes, $content );
3875
- }
3876
- /**
3877
- * set calendar component property trigger
3878
- *
3879
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3880
- * @since 2.9.9 - 2011-06-17
3881
- * @param mixed $year
3882
- * @param mixed $month optional
3883
- * @param int $day optional
3884
- * @param int $week optional
3885
- * @param int $hour optional
3886
- * @param int $min optional
3887
- * @param int $sec optional
3888
- * @param bool $relatedStart optional
3889
- * @param bool $before optional
3890
- * @param array $params optional
3891
- * @return bool
3892
- */
3893
- function setTrigger( $year, $month=null, $day=null, $week=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $relatedStart=TRUE, $before=TRUE, $params=FALSE ) {
3894
- if( empty( $year ) && empty( $month ) && empty( $day ) && empty( $week ) && empty( $hour ) && empty( $min ) && empty( $sec ))
3895
- if( $this->getConfig( 'allowEmpty' )) {
3896
- $this->trigger = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params ) );
3897
- return TRUE;
3898
- }
3899
- else
3900
- return FALSE;
3901
- if( iCalUtilityFunctions::_isArrayTimestampDate( $year )) { // timestamp
3902
- $params = iCalUtilityFunctions::_setParams( $month );
3903
- $date = iCalUtilityFunctions::_timestamp2date( $year, 7 );
3904
- foreach( $date as $k => $v )
3905
- $$k = $v;
3906
- }
3907
- elseif( is_array( $year ) && ( is_array( $month ) || empty( $month ))) {
3908
- $params = iCalUtilityFunctions::_setParams( $month );
3909
- if(!(array_key_exists( 'year', $year ) && // exclude date-time
3910
- array_key_exists( 'month', $year ) &&
3911
- array_key_exists( 'day', $year ))) { // when this must be a duration
3912
- if( isset( $params['RELATED'] ) && ( 'END' == strtoupper( $params['RELATED'] )))
3913
- $relatedStart = FALSE;
3914
- else
3915
- $relatedStart = ( array_key_exists( 'relatedStart', $year ) && ( TRUE !== $year['relatedStart'] )) ? FALSE : TRUE;
3916
- $before = ( array_key_exists( 'before', $year ) && ( TRUE !== $year['before'] )) ? FALSE : TRUE;
3917
- }
3918
- $SSYY = ( array_key_exists( 'year', $year )) ? $year['year'] : null;
3919
- $month = ( array_key_exists( 'month', $year )) ? $year['month'] : null;
3920
- $day = ( array_key_exists( 'day', $year )) ? $year['day'] : null;
3921
- $week = ( array_key_exists( 'week', $year )) ? $year['week'] : null;
3922
- $hour = ( array_key_exists( 'hour', $year )) ? $year['hour'] : 0; //null;
3923
- $min = ( array_key_exists( 'min', $year )) ? $year['min'] : 0; //null;
3924
- $sec = ( array_key_exists( 'sec', $year )) ? $year['sec'] : 0; //null;
3925
- $year = $SSYY;
3926
- }
3927
- elseif(is_string( $year ) && ( is_array( $month ) || empty( $month ))) { // duration or date in a string
3928
- $params = iCalUtilityFunctions::_setParams( $month );
3929
- if( in_array( $year[0], array( 'P', '+', '-' ))) { // duration
3930
- $relatedStart = ( isset( $params['RELATED'] ) && ( 'END' == strtoupper( $params['RELATED'] ))) ? FALSE : TRUE;
3931
- $before = ( '-' == $year[0] ) ? TRUE : FALSE;
3932
- if( 'P' != $year[0] )
3933
- $year = substr( $year, 1 );
3934
- $date = iCalUtilityFunctions::_duration_string( $year);
3935
- }
3936
- else // date
3937
- $date = iCalUtilityFunctions::_date_time_string( $year, 7 );
3938
- unset( $year, $month, $day );
3939
- if( empty( $date ))
3940
- $sec = 0;
3941
- else
3942
- foreach( $date as $k => $v )
3943
- $$k = $v;
3944
- }
3945
- else // single values in function input parameters
3946
- $params = iCalUtilityFunctions::_setParams( $params );
3947
- if( !empty( $year ) && !empty( $month ) && !empty( $day )) { // date
3948
- $params['VALUE'] = 'DATE-TIME';
3949
- $hour = ( $hour ) ? $hour : 0;
3950
- $min = ( $min ) ? $min : 0;
3951
- $sec = ( $sec ) ? $sec : 0;
3952
- $this->trigger = array( 'params' => $params );
3953
- $this->trigger['value'] = array( 'year' => $year
3954
- , 'month' => $month
3955
- , 'day' => $day
3956
- , 'hour' => $hour
3957
- , 'min' => $min
3958
- , 'sec' => $sec
3959
- , 'tz' => 'Z' );
3960
- return TRUE;
3961
- }
3962
- elseif(( empty( $year ) && empty( $month )) && // duration
3963
- (( !empty( $week ) || ( 0 == $week )) ||
3964
- ( !empty( $day ) || ( 0 == $day )) ||
3965
- ( !empty( $hour ) || ( 0 == $hour )) ||
3966
- ( !empty( $min ) || ( 0 == $min )) ||
3967
- ( !empty( $sec ) || ( 0 == $sec )))) {
3968
- unset( $params['RELATED'] ); // set at output creation (END only)
3969
- unset( $params['VALUE'] ); // 'DURATION' default
3970
- $this->trigger = array( 'params' => $params );
3971
- $this->trigger['value'] = array();
3972
- if( !empty( $week )) $this->trigger['value']['week'] = $week;
3973
- if( !empty( $day )) $this->trigger['value']['day'] = $day;
3974
- if( !empty( $hour )) $this->trigger['value']['hour'] = $hour;
3975
- if( !empty( $min )) $this->trigger['value']['min'] = $min;
3976
- if( !empty( $sec )) $this->trigger['value']['sec'] = $sec;
3977
- if( empty( $this->trigger['value'] )) {
3978
- $this->trigger['value']['sec'] = 0;
3979
- $before = FALSE;
3980
- }
3981
- $relatedStart = ( FALSE !== $relatedStart ) ? TRUE : FALSE;
3982
- $before = ( FALSE !== $before ) ? TRUE : FALSE;
3983
- $this->trigger['value']['relatedStart'] = $relatedStart;
3984
- $this->trigger['value']['before'] = $before;
3985
- return TRUE;
3986
- }
3987
- return FALSE;
3988
- }
3989
- /*********************************************************************************/
3990
- /**
3991
- * Property Name: TZID
3992
- */
3993
- /**
3994
- * creates formatted output for calendar component property tzid
3995
- *
3996
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3997
- * @since 2.4.8 - 2008-10-21
3998
- * @return string
3999
- */
4000
- function createTzid() {
4001
- if( empty( $this->tzid )) return FALSE;
4002
- if( empty( $this->tzid['value'] ))
4003
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZID' ) : FALSE;
4004
- $attributes = $this->_createParams( $this->tzid['params'] );
4005
- return $this->_createElement( 'TZID', $attributes, $this->_strrep( $this->tzid['value'] ));
4006
- }
4007
- /**
4008
- * set calendar component property tzid
4009
- *
4010
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4011
- * @since 2.4.8 - 2008-11-04
4012
- * @param string $value
4013
- * @param array $params optional
4014
- * @return bool
4015
- */
4016
- function setTzid( $value, $params=FALSE ) {
4017
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
4018
- $this->tzid = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
4019
- return TRUE;
4020
- }
4021
- /*********************************************************************************/
4022
- /**
4023
- * .. .
4024
- * Property Name: TZNAME
4025
- */
4026
- /**
4027
- * creates formatted output for calendar component property tzname
4028
- *
4029
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4030
- * @since 2.4.8 - 2008-10-21
4031
- * @return string
4032
- */
4033
- function createTzname() {
4034
- if( empty( $this->tzname )) return FALSE;
4035
- $output = null;
4036
- foreach( $this->tzname as $theName ) {
4037
- if( !empty( $theName['value'] )) {
4038
- $attributes = $this->_createParams( $theName['params'], array( 'LANGUAGE' ));
4039
- $output .= $this->_createElement( 'TZNAME', $attributes, $this->_strrep( $theName['value'] ));
4040
- }
4041
- elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'TZNAME' );
4042
- }
4043
- return $output;
4044
- }
4045
- /**
4046
- * set calendar component property tzname
4047
- *
4048
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4049
- * @since 2.5.1 - 2008-11-05
4050
- * @param string $value
4051
- * @param string $params, optional
4052
- * @param integer $index, optional
4053
- * @return bool
4054
- */
4055
- function setTzname( $value, $params=FALSE, $index=FALSE ) {
4056
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
4057
- iCalUtilityFunctions::_setMval( $this->tzname, $value, $params, FALSE, $index );
4058
- return TRUE;
4059
- }
4060
- /*********************************************************************************/
4061
- /**
4062
- * Property Name: TZOFFSETFROM
4063
- */
4064
- /**
4065
- * creates formatted output for calendar component property tzoffsetfrom
4066
- *
4067
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4068
- * @since 2.4.8 - 2008-10-21
4069
- * @return string
4070
- */
4071
- function createTzoffsetfrom() {
4072
- if( empty( $this->tzoffsetfrom )) return FALSE;
4073
- if( empty( $this->tzoffsetfrom['value'] ))
4074
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETFROM' ) : FALSE;
4075
- $attributes = $this->_createParams( $this->tzoffsetfrom['params'] );
4076
- return $this->_createElement( 'TZOFFSETFROM', $attributes, $this->tzoffsetfrom['value'] );
4077
- }
4078
- /**
4079
- * set calendar component property tzoffsetfrom
4080
- *
4081
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4082
- * @since 2.4.8 - 2008-11-04
4083
- * @param string $value
4084
- * @param string $params optional
4085
- * @return bool
4086
- */
4087
- function setTzoffsetfrom( $value, $params=FALSE ) {
4088
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
4089
- $this->tzoffsetfrom = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
4090
- return TRUE;
4091
- }
4092
- /*********************************************************************************/
4093
- /**
4094
- * Property Name: TZOFFSETTO
4095
- */
4096
- /**
4097
- * creates formatted output for calendar component property tzoffsetto
4098
- *
4099
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4100
- * @since 2.4.8 - 2008-10-21
4101
- * @return string
4102
- */
4103
- function createTzoffsetto() {
4104
- if( empty( $this->tzoffsetto )) return FALSE;
4105
- if( empty( $this->tzoffsetto['value'] ))
4106
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETTO' ) : FALSE;
4107
- $attributes = $this->_createParams( $this->tzoffsetto['params'] );
4108
- return $this->_createElement( 'TZOFFSETTO', $attributes, $this->tzoffsetto['value'] );
4109
- }
4110
- /**
4111
- * set calendar component property tzoffsetto
4112
- *
4113
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4114
- * @since 2.4.8 - 2008-11-04
4115
- * @param string $value
4116
- * @param string $params optional
4117
- * @return bool
4118
- */
4119
- function setTzoffsetto( $value, $params=FALSE ) {
4120
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
4121
- $this->tzoffsetto = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
4122
- return TRUE;
4123
- }
4124
- /*********************************************************************************/
4125
- /**
4126
- * Property Name: TZURL
4127
- */
4128
- /**
4129
- * creates formatted output for calendar component property tzurl
4130
- *
4131
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4132
- * @since 2.4.8 - 2008-10-21
4133
- * @return string
4134
- */
4135
- function createTzurl() {
4136
- if( empty( $this->tzurl )) return FALSE;
4137
- if( empty( $this->tzurl['value'] ))
4138
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZURL' ) : FALSE;
4139
- $attributes = $this->_createParams( $this->tzurl['params'] );
4140
- return $this->_createElement( 'TZURL', $attributes, $this->tzurl['value'] );
4141
- }
4142
- /**
4143
- * set calendar component property tzurl
4144
- *
4145
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4146
- * @since 2.4.8 - 2008-11-04
4147
- * @param string $value
4148
- * @param string $params optional
4149
- * @return boll
4150
- */
4151
- function setTzurl( $value, $params=FALSE ) {
4152
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
4153
- $this->tzurl = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
4154
- return TRUE;
4155
- }
4156
- /*********************************************************************************/
4157
- /**
4158
- * Property Name: UID
4159
- */
4160
- /**
4161
- * creates formatted output for calendar component property uid
4162
- *
4163
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4164
- * @since 0.9.7 - 2006-11-20
4165
- * @return string
4166
- */
4167
- function createUid() {
4168
- if( 0 >= count( $this->uid ))
4169
- $this->_makeuid();
4170
- $attributes = $this->_createParams( $this->uid['params'] );
4171
- return $this->_createElement( 'UID', $attributes, $this->uid['value'] );
4172
- }
4173
- /**
4174
- * create an unique id for this calendar component object instance
4175
- *
4176
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4177
- * @since 2.2.7 - 2007-09-04
4178
- * @return void
4179
- */
4180
- function _makeUid() {
4181
- $date = date('Ymd\THisT');
4182
- $unique = substr(microtime(), 2, 4);
4183
- $base = 'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPrRsStTuUvVxXuUvVwWzZ1234567890';
4184
- $start = 0;
4185
- $end = strlen( $base ) - 1;
4186
- $length = 6;
4187
- $str = null;
4188
- for( $p = 0; $p < $length; $p++ )
4189
- $unique .= $base{mt_rand( $start, $end )};
4190
- $this->uid = array( 'params' => null );
4191
- $this->uid['value'] = $date.'-'.$unique.'@'.$this->getConfig( 'unique_id' );
4192
- }
4193
- /**
4194
- * set calendar component property uid
4195
- *
4196
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4197
- * @since 2.4.8 - 2008-11-04
4198
- * @param string $value
4199
- * @param string $params optional
4200
- * @return bool
4201
- */
4202
- function setUid( $value, $params=FALSE ) {
4203
- if( empty( $value )) return FALSE; // no allowEmpty check here !!!!
4204
- $this->uid = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
4205
- return TRUE;
4206
- }
4207
- /*********************************************************************************/
4208
- /**
4209
- * Property Name: URL
4210
- */
4211
- /**
4212
- * creates formatted output for calendar component property url
4213
- *
4214
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4215
- * @since 2.4.8 - 2008-10-21
4216
- * @return string
4217
- */
4218
- function createUrl() {
4219
- if( empty( $this->url )) return FALSE;
4220
- if( empty( $this->url['value'] ))
4221
- return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'URL' ) : FALSE;
4222
- $attributes = $this->_createParams( $this->url['params'] );
4223
- return $this->_createElement( 'URL', $attributes, $this->url['value'] );
4224
- }
4225
- /**
4226
- * set calendar component property url
4227
- *
4228
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4229
- * @since 2.4.8 - 2008-11-04
4230
- * @param string $value
4231
- * @param string $params optional
4232
- * @return bool
4233
- */
4234
- function setUrl( $value, $params=FALSE ) {
4235
- if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
4236
- $this->url = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
4237
- return TRUE;
4238
- }
4239
- /*********************************************************************************/
4240
- /**
4241
- * Property Name: x-prop
4242
- */
4243
- /**
4244
- * creates formatted output for calendar component property x-prop
4245
- *
4246
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4247
- * @since 2.9.3 - 2011-05-14
4248
- * @return string
4249
- */
4250
- function createXprop() {
4251
- if( empty( $this->xprop )) return FALSE;
4252
- $output = null;
4253
- foreach( $this->xprop as $label => $xpropPart ) {
4254
- if( !isset($xpropPart['value']) || ( empty( $xpropPart['value'] ) && !is_numeric( $xpropPart['value'] ))) {
4255
- if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( $label );
4256
- continue;
4257
- }
4258
- $attributes = $this->_createParams( $xpropPart['params'], array( 'LANGUAGE' ));
4259
- if( is_array( $xpropPart['value'] )) {
4260
- foreach( $xpropPart['value'] as $pix => $theXpart )
4261
- $xpropPart['value'][$pix] = $this->_strrep( $theXpart );
4262
- $xpropPart['value'] = implode( ',', $xpropPart['value'] );
4263
- }
4264
- else
4265
- $xpropPart['value'] = $this->_strrep( $xpropPart['value'] );
4266
- $output .= $this->_createElement( $label, $attributes, $xpropPart['value'] );
4267
- }
4268
- return $output;
4269
- }
4270
- /**
4271
- * set calendar component property x-prop
4272
- *
4273
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4274
- * @since 2.9.3 - 2011-05-14
4275
- * @param string $label
4276
- * @param mixed $value
4277
- * @param array $params optional
4278
- * @return bool
4279
- */
4280
- function setXprop( $label, $value, $params=FALSE ) {
4281
- if( empty( $label )) return;
4282
- if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
4283
- $xprop = array( 'value' => $value );
4284
- $xprop['params'] = iCalUtilityFunctions::_setParams( $params );
4285
- if( !is_array( $this->xprop )) $this->xprop = array();
4286
- $this->xprop[strtoupper( $label )] = $xprop;
4287
- return TRUE;
4288
- }
4289
- /*********************************************************************************/
4290
- /*********************************************************************************/
4291
- /**
4292
- * create element format parts
4293
- *
4294
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4295
- * @since 2.0.6 - 2006-06-20
4296
- * @return string
4297
- */
4298
- function _createFormat() {
4299
- $objectname = null;
4300
- switch( $this->format ) {
4301
- case 'xcal':
4302
- $objectname = ( isset( $this->timezonetype )) ?
4303
- strtolower( $this->timezonetype ) : strtolower( $this->objName );
4304
- $this->componentStart1 = $this->elementStart1 = '<';
4305
- $this->componentStart2 = $this->elementStart2 = '>';
4306
- $this->componentEnd1 = $this->elementEnd1 = '</';
4307
- $this->componentEnd2 = $this->elementEnd2 = '>'.$this->nl;
4308
- $this->intAttrDelimiter = '<!-- -->';
4309
- $this->attributeDelimiter = $this->nl;
4310
- $this->valueInit = null;
4311
- break;
4312
- default:
4313
- $objectname = ( isset( $this->timezonetype )) ?
4314
- strtoupper( $this->timezonetype ) : strtoupper( $this->objName );
4315
- $this->componentStart1 = 'BEGIN:';
4316
- $this->componentStart2 = null;
4317
- $this->componentEnd1 = 'END:';
4318
- $this->componentEnd2 = $this->nl;
4319
- $this->elementStart1 = null;
4320
- $this->elementStart2 = null;
4321
- $this->elementEnd1 = null;
4322
- $this->elementEnd2 = $this->nl;
4323
- $this->intAttrDelimiter = '<!-- -->';
4324
- $this->attributeDelimiter = ';';
4325
- $this->valueInit = ':';
4326
- break;
4327
- }
4328
- return $objectname;
4329
- }
4330
- /**
4331
- * creates formatted output for calendar component property
4332
- *
4333
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4334
- * @since 2.6.22 - 2010-12-06
4335
- * @param string $label property name
4336
- * @param string $attributes property attributes
4337
- * @param string $content property content (optional)
4338
- * @return string
4339
- */
4340
- function _createElement( $label, $attributes=null, $content=FALSE ) {
4341
- switch( $this->format ) {
4342
- case 'xcal':
4343
- $label = strtolower( $label );
4344
- break;
4345
- default:
4346
- $label = strtoupper( $label );
4347
- break;
4348
- }
4349
- $output = $this->elementStart1.$label;
4350
- $categoriesAttrLang = null;
4351
- $attachInlineBinary = FALSE;
4352
- $attachfmttype = null;
4353
- if( !empty( $attributes )) {
4354
- $attributes = trim( $attributes );
4355
- if ( 'xcal' == $this->format) {
4356
- $attributes2 = explode( $this->intAttrDelimiter, $attributes );
4357
- $attributes = null;
4358
- foreach( $attributes2 as $attribute ) {
4359
- $attrKVarr = explode( '=', $attribute );
4360
- if( empty( $attrKVarr[0] ))
4361
- continue;
4362
- if( !isset( $attrKVarr[1] )) {
4363
- $attrValue = $attrKVarr[0];
4364
- $attrKey = null;
4365
- }
4366
- elseif( 2 == count( $attrKVarr)) {
4367
- $attrKey = strtolower( $attrKVarr[0] );
4368
- $attrValue = $attrKVarr[1];
4369
- }
4370
- else {
4371
- $attrKey = strtolower( $attrKVarr[0] );
4372
- unset( $attrKVarr[0] );
4373
- $attrValue = implode( '=', $attrKVarr );
4374
- }
4375
- if(( 'attach' == $label ) && ( in_array( $attrKey, array( 'fmttype', 'encoding', 'value' )))) {
4376
- $attachInlineBinary = TRUE;
4377
- if( 'fmttype' == $attrKey )
4378
- $attachfmttype = $attrKey.'='.$attrValue;
4379
- continue;
4380
- }
4381
- elseif(( 'categories' == $label ) && ( 'language' == $attrKey ))
4382
- $categoriesAttrLang = $attrKey.'='.$attrValue;
4383
- else {
4384
- $attributes .= ( empty( $attributes )) ? ' ' : $this->attributeDelimiter.' ';
4385
- $attributes .= ( !empty( $attrKey )) ? $attrKey.'=' : null;
4386
- if(( '"' == substr( $attrValue, 0, 1 )) && ( '"' == substr( $attrValue, -1 ))) {
4387
- $attrValue = substr( $attrValue, 1, ( strlen( $attrValue ) - 2 ));
4388
- $attrValue = str_replace( '"', '', $attrValue );
4389
- }
4390
- $attributes .= '"'.htmlspecialchars( $attrValue ).'"';
4391
- }
4392
- }
4393
- }
4394
- else {
4395
- $attributes = str_replace( $this->intAttrDelimiter, $this->attributeDelimiter, $attributes );
4396
- }
4397
- }
4398
- if(((( 'attach' == $label ) && !$attachInlineBinary ) ||
4399
- ( in_array( $label, array( 'tzurl', 'url' )))) && ( 'xcal' == $this->format)) {
4400
- $pos = strrpos($content, "/");
4401
- $docname = ( $pos !== false) ? substr( $content, (1 - strlen( $content ) + $pos )) : $content;
4402
- $this->xcaldecl[] = array( 'xmldecl' => 'ENTITY'
4403
- , 'uri' => $docname
4404
- , 'ref' => 'SYSTEM'
4405
- , 'external' => $content
4406
- , 'type' => 'NDATA'
4407
- , 'type2' => 'BINERY' );
4408
- $attributes .= ( empty( $attributes )) ? ' ' : $this->attributeDelimiter.' ';
4409
- $attributes .= 'uri="'.$docname.'"';
4410
- $content = null;
4411
- if( 'attach' == $label ) {
4412
- $attributes = str_replace( $this->attributeDelimiter, $this->intAttrDelimiter, $attributes );
4413
- $content = $this->_createElement( 'extref', $attributes, null );
4414
- $attributes = null;
4415
- }
4416
- }
4417
- elseif(( 'attach' == $label ) && $attachInlineBinary && ( 'xcal' == $this->format)) {
4418
- $content = $this->nl.$this->_createElement( 'b64bin', $attachfmttype, $content ); // max one attribute
4419
- }
4420
- $output .= $attributes;
4421
- if( !$content && ( '0' != $content )) {
4422
- switch( $this->format ) {
4423
- case 'xcal':
4424
- $output .= ' /';
4425
- $output .= $this->elementStart2;
4426
- return $output;
4427
- break;
4428
- default:
4429
- $output .= $this->elementStart2.$this->valueInit;
4430
- return $this->_size75( $output );
4431
- break;
4432
- }
4433
- }
4434
- $output .= $this->elementStart2;
4435
- $output .= $this->valueInit.$content;
4436
- switch( $this->format ) {
4437
- case 'xcal':
4438
- return $output.$this->elementEnd1.$label.$this->elementEnd2;
4439
- break;
4440
- default:
4441
- return $this->_size75( $output );
4442
- break;
4443
- }
4444
- }
4445
- /**
4446
- * creates formatted output for calendar component property parameters
4447
- *
4448
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4449
- * @since 2.6.33 - 2010-12-18
4450
- * @param array $params optional
4451
- * @param array $ctrKeys optional
4452
- * @return string
4453
- */
4454
- function _createParams( $params=array(), $ctrKeys=array() ) {
4455
- if( !is_array( $params ) || empty( $params ))
4456
- $params = array();
4457
- $attrLANG = $attr1 = $attr2 = $lang = null;
4458
- $CNattrKey = ( in_array( 'CN', $ctrKeys )) ? TRUE : FALSE ;
4459
- $LANGattrKey = ( in_array( 'LANGUAGE', $ctrKeys )) ? TRUE : FALSE ;
4460
- $CNattrExist = $LANGattrExist = FALSE;
4461
- $xparams = array();
4462
- foreach( $params as $paramKey => $paramValue ) {
4463
- if( ctype_digit( (string) $paramKey )) {
4464
- $xparams[] = $paramValue;
4465
- continue;
4466
- }
4467
- $paramKey = strtoupper( $paramKey );
4468
- if( !in_array( $paramKey, array( 'ALTREP', 'CN', 'DIR', 'ENCODING', 'FMTTYPE', 'LANGUAGE', 'RANGE', 'RELTYPE', 'SENT-BY', 'TZID', 'VALUE' )))
4469
- $xparams[$paramKey] = $paramValue;
4470
- else
4471
- $params[$paramKey] = $paramValue;
4472
- }
4473
- ksort( $xparams, SORT_STRING );
4474
- foreach( $xparams as $paramKey => $paramValue ) {
4475
- if( ctype_digit( (string) $paramKey ))
4476
- $attr2 .= $this->intAttrDelimiter.$paramValue;
4477
- else
4478
- $attr2 .= $this->intAttrDelimiter."$paramKey=$paramValue";
4479
- }
4480
- if( isset( $params['FMTTYPE'] ) && !in_array( 'FMTTYPE', $ctrKeys )) {
4481
- $attr1 .= $this->intAttrDelimiter.'FMTTYPE='.$params['FMTTYPE'].$attr2;
4482
- $attr2 = null;
4483
- }
4484
- if( isset( $params['ENCODING'] ) && !in_array( 'ENCODING', $ctrKeys )) {
4485
- if( !empty( $attr2 )) {
4486
- $attr1 .= $attr2;
4487
- $attr2 = null;
4488
- }
4489
- $attr1 .= $this->intAttrDelimiter.'ENCODING='.$params['ENCODING'];
4490
- }
4491
- if( isset( $params['VALUE'] ) && !in_array( 'VALUE', $ctrKeys ))
4492
- $attr1 .= $this->intAttrDelimiter.'VALUE='.$params['VALUE'];
4493
- if( isset( $params['TZID'] ) && !in_array( 'TZID', $ctrKeys ))
4494
- $attr1 .= $this->intAttrDelimiter.'TZID='.$params['TZID'];
4495
- if( isset( $params['RANGE'] ) && !in_array( 'RANGE', $ctrKeys ))
4496
- $attr1 .= $this->intAttrDelimiter.'RANGE='.$params['RANGE'];
4497
- if( isset( $params['RELTYPE'] ) && !in_array( 'RELTYPE', $ctrKeys ))
4498
- $attr1 .= $this->intAttrDelimiter.'RELTYPE='.$params['RELTYPE'];
4499
- if( isset( $params['CN'] ) && $CNattrKey ) {
4500
- $attr1 = $this->intAttrDelimiter.'CN="'.$params['CN'].'"';
4501
- $CNattrExist = TRUE;
4502
- }
4503
- if( isset( $params['DIR'] ) && in_array( 'DIR', $ctrKeys ))
4504
- $attr1 .= $this->intAttrDelimiter.'DIR="'.$params['DIR'].'"';
4505
- if( isset( $params['SENT-BY'] ) && in_array( 'SENT-BY', $ctrKeys ))
4506
- $attr1 .= $this->intAttrDelimiter.'SENT-BY="'.$params['SENT-BY'].'"';
4507
- if( isset( $params['ALTREP'] ) && in_array( 'ALTREP', $ctrKeys ))
4508
- $attr1 .= $this->intAttrDelimiter.'ALTREP="'.$params['ALTREP'].'"';
4509
- if( isset( $params['LANGUAGE'] ) && $LANGattrKey ) {
4510
- $attrLANG .= $this->intAttrDelimiter.'LANGUAGE='.$params['LANGUAGE'];
4511
- $LANGattrExist = TRUE;
4512
- }
4513
- if( !$LANGattrExist ) {
4514
- $lang = $this->getConfig( 'language' );
4515
- if(( $CNattrExist || $LANGattrKey ) && $lang )
4516
- $attrLANG .= $this->intAttrDelimiter.'LANGUAGE='.$lang;
4517
- }
4518
- return $attr1.$attrLANG.$attr2;
4519
- }
4520
- /**
4521
- * creates formatted output for calendar component property data value type recur
4522
- *
4523
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4524
- * @since 2.4.8 - 2008-10-22
4525
- * @param array $recurlabel
4526
- * @param array $recurdata
4527
- * @return string
4528
- */
4529
- function _format_recur( $recurlabel, $recurdata ) {
4530
- $output = null;
4531
- foreach( $recurdata as $therule ) {
4532
- if( empty( $therule['value'] )) {
4533
- if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( $recurlabel );
4534
- continue;
4535
- }
4536
- $attributes = ( isset( $therule['params'] )) ? $this->_createParams( $therule['params'] ) : null;
4537
- $content1 = $content2 = null;
4538
- foreach( $therule['value'] as $rulelabel => $rulevalue ) {
4539
- switch( $rulelabel ) {
4540
- case 'FREQ': {
4541
- $content1 .= "FREQ=$rulevalue";
4542
- break;
4543
- }
4544
- case 'UNTIL': {
4545
- $content2 .= ";UNTIL=";
4546
- $content2 .= iCalUtilityFunctions::_format_date_time( $rulevalue );
4547
- break;
4548
- }
4549
- case 'COUNT':
4550
- case 'INTERVAL':
4551
- case 'WKST': {
4552
- $content2 .= ";$rulelabel=$rulevalue";
4553
- break;
4554
- }
4555
- case 'BYSECOND':
4556
- case 'BYMINUTE':
4557
- case 'BYHOUR':
4558
- case 'BYMONTHDAY':
4559
- case 'BYYEARDAY':
4560
- case 'BYWEEKNO':
4561
- case 'BYMONTH':
4562
- case 'BYSETPOS': {
4563
- $content2 .= ";$rulelabel=";
4564
- if( is_array( $rulevalue )) {
4565
- foreach( $rulevalue as $vix => $valuePart ) {
4566
- $content2 .= ( $vix ) ? ',' : null;
4567
- $content2 .= $valuePart;
4568
- }
4569
- }
4570
- else
4571
- $content2 .= $rulevalue;
4572
- break;
4573
- }
4574
- case 'BYDAY': {
4575
- $content2 .= ";$rulelabel=";
4576
- $bydaycnt = 0;
4577
- foreach( $rulevalue as $vix => $valuePart ) {
4578
- $content21 = $content22 = null;
4579
- if( is_array( $valuePart )) {
4580
- $content2 .= ( $bydaycnt ) ? ',' : null;
4581
- foreach( $valuePart as $vix2 => $valuePart2 ) {
4582
- if( 'DAY' != strtoupper( $vix2 ))
4583
- $content21 .= $valuePart2;
4584
- else
4585
- $content22 .= $valuePart2;
4586
- }
4587
- $content2 .= $content21.$content22;
4588
- $bydaycnt++;
4589
- }
4590
- else {
4591
- $content2 .= ( $bydaycnt ) ? ',' : null;
4592
- if( 'DAY' != strtoupper( $vix ))
4593
- $content21 .= $valuePart;
4594
- else {
4595
- $content22 .= $valuePart;
4596
- $bydaycnt++;
4597
- }
4598
- $content2 .= $content21.$content22;
4599
- }
4600
- }
4601
- break;
4602
- }
4603
- default: {
4604
- $content2 .= ";$rulelabel=$rulevalue";
4605
- break;
4606
- }
4607
- }
4608
- }
4609
- $output .= $this->_createElement( $recurlabel, $attributes, $content1.$content2 );
4610
- }
4611
- return $output;
4612
- }
4613
- /**
4614
- * check if property not exists within component
4615
- *
4616
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4617
- * @since 2.5.1 - 2008-10-15
4618
- * @param string $propName
4619
- * @return bool
4620
- */
4621
- function _notExistProp( $propName ) {
4622
- if( empty( $propName )) return FALSE; // when deleting x-prop, an empty propName may be used=allowed
4623
- $propName = strtolower( $propName );
4624
- if( 'last-modified' == $propName ) { if( !isset( $this->lastmodified )) return TRUE; }
4625
- elseif( 'percent-complete' == $propName ) { if( !isset( $this->percentcomplete )) return TRUE; }
4626
- elseif( 'recurrence-id' == $propName ) { if( !isset( $this->recurrenceid )) return TRUE; }
4627
- elseif( 'related-to' == $propName ) { if( !isset( $this->relatedto )) return TRUE; }
4628
- elseif( 'request-status' == $propName ) { if( !isset( $this->requeststatus )) return TRUE; }
4629
- elseif(( 'x-' != substr($propName,0,2)) && !isset( $this->$propName )) return TRUE;
4630
- return FALSE;
4631
- }
4632
- /*********************************************************************************/
4633
- /*********************************************************************************/
4634
- /**
4635
- * get general component config variables or info about subcomponents
4636
- *
4637
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4638
- * @since 2.9.6 - 2011-05-14
4639
- * @param mixed $config
4640
- * @return value
4641
- */
4642
- function getConfig( $config = FALSE) {
4643
- if( !$config ) {
4644
- $return = array();
4645
- $return['ALLOWEMPTY'] = $this->getConfig( 'ALLOWEMPTY' );
4646
- $return['FORMAT'] = $this->getConfig( 'FORMAT' );
4647
- if( FALSE !== ( $lang = $this->getConfig( 'LANGUAGE' )))
4648
- $return['LANGUAGE'] = $lang;
4649
- $return['NEWLINECHAR'] = $this->getConfig( 'NEWLINECHAR' );
4650
- $return['TZTD'] = $this->getConfig( 'TZID' );
4651
- $return['UNIQUE_ID'] = $this->getConfig( 'UNIQUE_ID' );
4652
- return $return;
4653
- }
4654
- switch( strtoupper( $config )) {
4655
- case 'ALLOWEMPTY':
4656
- return $this->allowEmpty;
4657
- break;
4658
- case 'COMPSINFO':
4659
- unset( $this->compix );
4660
- $info = array();
4661
- if( isset( $this->components )) {
4662
- foreach( $this->components as $cix => $component ) {
4663
- if( empty( $component )) continue;
4664
- $info[$cix]['ordno'] = $cix + 1;
4665
- $info[$cix]['type'] = $component->objName;
4666
- $info[$cix]['uid'] = $component->getProperty( 'uid' );
4667
- $info[$cix]['props'] = $component->getConfig( 'propinfo' );
4668
- $info[$cix]['sub'] = $component->getConfig( 'compsinfo' );
4669
- }
4670
- }
4671
- return $info;
4672
- break;
4673
- case 'FORMAT':
4674
- return $this->format;
4675
- break;
4676
- case 'LANGUAGE':
4677
- // get language for calendar component as defined in [RFC 1766]
4678
- return $this->language;
4679
- break;
4680
- case 'NL':
4681
- case 'NEWLINECHAR':
4682
- return $this->nl;
4683
- break;
4684
- case 'PROPINFO':
4685
- $output = array();
4686
- if( !in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) {
4687
- if( empty( $this->uid['value'] )) $this->_makeuid();
4688
- $output['UID'] = 1;
4689
- }
4690
- if( !empty( $this->dtstamp )) $output['DTSTAMP'] = 1;
4691
- if( !empty( $this->summary )) $output['SUMMARY'] = 1;
4692
- if( !empty( $this->description )) $output['DESCRIPTION'] = count( $this->description );
4693
- if( !empty( $this->dtstart )) $output['DTSTART'] = 1;
4694
- if( !empty( $this->dtend )) $output['DTEND'] = 1;
4695
- if( !empty( $this->due )) $output['DUE'] = 1;
4696
- if( !empty( $this->duration )) $output['DURATION'] = 1;
4697
- if( !empty( $this->rrule )) $output['RRULE'] = count( $this->rrule );
4698
- if( !empty( $this->rdate )) $output['RDATE'] = count( $this->rdate );
4699
- if( !empty( $this->exdate )) $output['EXDATE'] = count( $this->exdate );
4700
- if( !empty( $this->exrule )) $output['EXRULE'] = count( $this->exrule );
4701
- if( !empty( $this->action )) $output['ACTION'] = 1;
4702
- if( !empty( $this->attach )) $output['ATTACH'] = count( $this->attach );
4703
- if( !empty( $this->attendee )) $output['ATTENDEE'] = count( $this->attendee );
4704
- if( !empty( $this->categories )) $output['CATEGORIES'] = count( $this->categories );
4705
- if( !empty( $this->class )) $output['CLASS'] = 1;
4706
- if( !empty( $this->comment )) $output['COMMENT'] = count( $this->comment );
4707
- if( !empty( $this->completed )) $output['COMPLETED'] = 1;
4708
- if( !empty( $this->contact )) $output['CONTACT'] = count( $this->contact );
4709
- if( !empty( $this->created )) $output['CREATED'] = 1;
4710
- if( !empty( $this->freebusy )) $output['FREEBUSY'] = count( $this->freebusy );
4711
- if( !empty( $this->geo )) $output['GEO'] = 1;
4712
- if( !empty( $this->lastmodified )) $output['LAST-MODIFIED'] = 1;
4713
- if( !empty( $this->location )) $output['LOCATION'] = 1;
4714
- if( !empty( $this->organizer )) $output['ORGANIZER'] = 1;
4715
- if( !empty( $this->percentcomplete )) $output['PERCENT-COMPLETE'] = 1;
4716
- if( !empty( $this->priority )) $output['PRIORITY'] = 1;
4717
- if( !empty( $this->recurrenceid )) $output['RECURRENCE-ID'] = 1;
4718
- if( !empty( $this->relatedto )) $output['RELATED-TO'] = count( $this->relatedto );
4719
- if( !empty( $this->repeat )) $output['REPEAT'] = 1;
4720
- if( !empty( $this->requeststatus )) $output['REQUEST-STATUS'] = count( $this->requeststatus );
4721
- if( !empty( $this->resources )) $output['RESOURCES'] = count( $this->resources );
4722
- if( !empty( $this->sequence )) $output['SEQUENCE'] = 1;
4723
- if( !empty( $this->sequence )) $output['SEQUENCE'] = 1;
4724
- if( !empty( $this->status )) $output['STATUS'] = 1;
4725
- if( !empty( $this->transp )) $output['TRANSP'] = 1;
4726
- if( !empty( $this->trigger )) $output['TRIGGER'] = 1;
4727
- if( !empty( $this->tzid )) $output['TZID'] = 1;
4728
- if( !empty( $this->tzname )) $output['TZNAME'] = count( $this->tzname );
4729
- if( !empty( $this->tzoffsetfrom )) $output['TZOFFSETFROM'] = 1;
4730
- if( !empty( $this->tzoffsetto )) $output['TZOFFSETTO'] = 1;
4731
- if( !empty( $this->tzurl )) $output['TZURL'] = 1;
4732
- if( !empty( $this->url )) $output['URL'] = 1;
4733
- if( !empty( $this->xprop )) $output['X-PROP'] = count( $this->xprop );
4734
- return $output;
4735
- break;
4736
- case 'TZID':
4737
- return $this->dtzid;
4738
- break;
4739
- case 'UNIQUE_ID':
4740
- if( empty( $this->unique_id ))
4741
- $this->unique_id = ( isset( $_SERVER['SERVER_NAME'] )) ? gethostbyname( $_SERVER['SERVER_NAME'] ) : 'localhost';
4742
- return $this->unique_id;
4743
- break;
4744
- }
4745
- }
4746
- /**
4747
- * general component config setting
4748
- *
4749
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4750
- * @since 2.9.6 - 2011-05-14
4751
- * @param mixed $config
4752
- * @param string $value
4753
- * @param bool $softUpdate
4754
- * @return void
4755
- */
4756
- function setConfig( $config, $value = FALSE, $softUpdate = FALSE ) {
4757
- if( is_array( $config )) {
4758
- foreach( $config as $cKey => $cValue ) {
4759
- if( FALSE === $this->setConfig( $cKey, $cValue, $softUpdate ))
4760
- return FALSE;
4761
- }
4762
- return TRUE;
4763
- }
4764
- $res = FALSE;
4765
- switch( strtoupper( $config )) {
4766
- case 'ALLOWEMPTY':
4767
- $this->allowEmpty = $value;
4768
- $subcfg = array( 'ALLOWEMPTY' => $value );
4769
- $res = TRUE;
4770
- break;
4771
- case 'FORMAT':
4772
- $value = trim( strtolower( $value ));
4773
- $this->format = $value;
4774
- $this->_createFormat();
4775
- $subcfg = array( 'FORMAT' => $value );
4776
- $res = TRUE;
4777
- break;
4778
- case 'LANGUAGE':
4779
- // set language for calendar component as defined in [RFC 1766]
4780
- $value = trim( $value );
4781
- if( empty( $this->language ) || !$softUpdate )
4782
- $this->language = $value;
4783
- $subcfg = array( 'LANGUAGE' => $value );
4784
- $res = TRUE;
4785
- break;
4786
- case 'NL':
4787
- case 'NEWLINECHAR':
4788
- $this->nl = $value;
4789
- $subcfg = array( 'NL' => $value );
4790
- $res = TRUE;
4791
- break;
4792
- case 'TZID':
4793
- $this->dtzid = $value;
4794
- $subcfg = array( 'TZID' => $value );
4795
- $res = TRUE;
4796
- break;
4797
- case 'UNIQUE_ID':
4798
- $value = trim( $value );
4799
- $this->unique_id = $value;
4800
- $subcfg = array( 'UNIQUE_ID' => $value );
4801
- $res = TRUE;
4802
- break;
4803
- default: // any unvalid config key.. .
4804
- return TRUE;
4805
- }
4806
- if( !$res ) return FALSE;
4807
- if( isset( $subcfg ) && !empty( $this->components )) {
4808
- foreach( $subcfg as $cfgkey => $cfgvalue ) {
4809
- foreach( $this->components as $cix => $component ) {
4810
- $res = $component->setConfig( $cfgkey, $cfgvalue, $softUpdate );
4811
- if( !$res )
4812
- break 2;
4813
- $this->components[$cix] = $component->copy(); // PHP4 compliant
4814
- }
4815
- }
4816
- }
4817
- return $res;
4818
- }
4819
- /*********************************************************************************/
4820
- /**
4821
- * delete component property value
4822
- *
4823
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4824
- * @since 2.8.8 - 2011-03-15
4825
- * @param mixed $propName, bool FALSE => X-property
4826
- * @param int $propix, optional, if specific property is wanted in case of multiply occurences
4827
- * @return bool, if successfull delete TRUE
4828
- */
4829
- function deleteProperty( $propName=FALSE, $propix=FALSE ) {
4830
- if( $this->_notExistProp( $propName )) return FALSE;
4831
- $propName = strtoupper( $propName );
4832
- if( in_array( $propName, array( 'ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION', 'EXDATE', 'EXRULE',
4833
- 'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME', 'X-PROP' ))) {
4834
- if( !$propix )
4835
- $propix = ( isset( $this->propdelix[$propName] ) && ( 'X-PROP' != $propName )) ? $this->propdelix[$propName] + 2 : 1;
4836
- $this->propdelix[$propName] = --$propix;
4837
- }
4838
- $return = FALSE;
4839
- switch( $propName ) {
4840
- case 'ACTION':
4841
- if( !empty( $this->action )) {
4842
- $this->action = '';
4843
- $return = TRUE;
4844
- }
4845
- break;
4846
- case 'ATTACH':
4847
- return $this->deletePropertyM( $this->attach, $this->propdelix[$propName] );
4848
- break;
4849
- case 'ATTENDEE':
4850
- return $this->deletePropertyM( $this->attendee, $this->propdelix[$propName] );
4851
- break;
4852
- case 'CATEGORIES':
4853
- return $this->deletePropertyM( $this->categories, $this->propdelix[$propName] );
4854
- break;
4855
- case 'CLASS':
4856
- if( !empty( $this->class )) {
4857
- $this->class = '';
4858
- $return = TRUE;
4859
- }
4860
- break;
4861
- case 'COMMENT':
4862
- return $this->deletePropertyM( $this->comment, $this->propdelix[$propName] );
4863
- break;
4864
- case 'COMPLETED':
4865
- if( !empty( $this->completed )) {
4866
- $this->completed = '';
4867
- $return = TRUE;
4868
- }
4869
- break;
4870
- case 'CONTACT':
4871
- return $this->deletePropertyM( $this->contact, $this->propdelix[$propName] );
4872
- break;
4873
- case 'CREATED':
4874
- if( !empty( $this->created )) {
4875
- $this->created = '';
4876
- $return = TRUE;
4877
- }
4878
- break;
4879
- case 'DESCRIPTION':
4880
- return $this->deletePropertyM( $this->description, $this->propdelix[$propName] );
4881
- break;
4882
- case 'DTEND':
4883
- if( !empty( $this->dtend )) {
4884
- $this->dtend = '';
4885
- $return = TRUE;
4886
- }
4887
- break;
4888
- case 'DTSTAMP':
4889
- if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
4890
- return FALSE;
4891
- if( !empty( $this->dtstamp )) {
4892
- $this->dtstamp = '';
4893
- $return = TRUE;
4894
- }
4895
- break;
4896
- case 'DTSTART':
4897
- if( !empty( $this->dtstart )) {
4898
- $this->dtstart = '';
4899
- $return = TRUE;
4900
- }
4901
- break;
4902
- case 'DUE':
4903
- if( !empty( $this->due )) {
4904
- $this->due = '';
4905
- $return = TRUE;
4906
- }
4907
- break;
4908
- case 'DURATION':
4909
- if( !empty( $this->duration )) {
4910
- $this->duration = '';
4911
- $return = TRUE;
4912
- }
4913
- break;
4914
- case 'EXDATE':
4915
- return $this->deletePropertyM( $this->exdate, $this->propdelix[$propName] );
4916
- break;
4917
- case 'EXRULE':
4918
- return $this->deletePropertyM( $this->exrule, $this->propdelix[$propName] );
4919
- break;
4920
- case 'FREEBUSY':
4921
- return $this->deletePropertyM( $this->freebusy, $this->propdelix[$propName] );
4922
- break;
4923
- case 'GEO':
4924
- if( !empty( $this->geo )) {
4925
- $this->geo = '';
4926
- $return = TRUE;
4927
- }
4928
- break;
4929
- case 'LAST-MODIFIED':
4930
- if( !empty( $this->lastmodified )) {
4931
- $this->lastmodified = '';
4932
- $return = TRUE;
4933
- }
4934
- break;
4935
- case 'LOCATION':
4936
- if( !empty( $this->location )) {
4937
- $this->location = '';
4938
- $return = TRUE;
4939
- }
4940
- break;
4941
- case 'ORGANIZER':
4942
- if( !empty( $this->organizer )) {
4943
- $this->organizer = '';
4944
- $return = TRUE;
4945
- }
4946
- break;
4947
- case 'PERCENT-COMPLETE':
4948
- if( !empty( $this->percentcomplete )) {
4949
- $this->percentcomplete = '';
4950
- $return = TRUE;
4951
- }
4952
- break;
4953
- case 'PRIORITY':
4954
- if( !empty( $this->priority )) {
4955
- $this->priority = '';
4956
- $return = TRUE;
4957
- }
4958
- break;
4959
- case 'RDATE':
4960
- return $this->deletePropertyM( $this->rdate, $this->propdelix[$propName] );
4961
- break;
4962
- case 'RECURRENCE-ID':
4963
- if( !empty( $this->recurrenceid )) {
4964
- $this->recurrenceid = '';
4965
- $return = TRUE;
4966
- }
4967
- break;
4968
- case 'RELATED-TO':
4969
- return $this->deletePropertyM( $this->relatedto, $this->propdelix[$propName] );
4970
- break;
4971
- case 'REPEAT':
4972
- if( !empty( $this->repeat )) {
4973
- $this->repeat = '';
4974
- $return = TRUE;
4975
- }
4976
- break;
4977
- case 'REQUEST-STATUS':
4978
- return $this->deletePropertyM( $this->requeststatus, $this->propdelix[$propName] );
4979
- break;
4980
- case 'RESOURCES':
4981
- return $this->deletePropertyM( $this->resources, $this->propdelix[$propName] );
4982
- break;
4983
- case 'RRULE':
4984
- return $this->deletePropertyM( $this->rrule, $this->propdelix[$propName] );
4985
- break;
4986
- case 'SEQUENCE':
4987
- if( !empty( $this->sequence )) {
4988
- $this->sequence = '';
4989
- $return = TRUE;
4990
- }
4991
- break;
4992
- case 'STATUS':
4993
- if( !empty( $this->status )) {
4994
- $this->status = '';
4995
- $return = TRUE;
4996
- }
4997
- break;
4998
- case 'SUMMARY':
4999
- if( !empty( $this->summary )) {
5000
- $this->summary = '';
5001
- $return = TRUE;
5002
- }
5003
- break;
5004
- case 'TRANSP':
5005
- if( !empty( $this->transp )) {
5006
- $this->transp = '';
5007
- $return = TRUE;
5008
- }
5009
- break;
5010
- case 'TRIGGER':
5011
- if( !empty( $this->trigger )) {
5012
- $this->trigger = '';
5013
- $return = TRUE;
5014
- }
5015
- break;
5016
- case 'TZID':
5017
- if( !empty( $this->tzid )) {
5018
- $this->tzid = '';
5019
- $return = TRUE;
5020
- }
5021
- break;
5022
- case 'TZNAME':
5023
- return $this->deletePropertyM( $this->tzname, $this->propdelix[$propName] );
5024
- break;
5025
- case 'TZOFFSETFROM':
5026
- if( !empty( $this->tzoffsetfrom )) {
5027
- $this->tzoffsetfrom = '';
5028
- $return = TRUE;
5029
- }
5030
- break;
5031
- case 'TZOFFSETTO':
5032
- if( !empty( $this->tzoffsetto )) {
5033
- $this->tzoffsetto = '';
5034
- $return = TRUE;
5035
- }
5036
- break;
5037
- case 'TZURL':
5038
- if( !empty( $this->tzurl )) {
5039
- $this->tzurl = '';
5040
- $return = TRUE;
5041
- }
5042
- break;
5043
- case 'UID':
5044
- if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
5045
- return FALSE;
5046
- if( !empty( $this->uid )) {
5047
- $this->uid = '';
5048
- $return = TRUE;
5049
- }
5050
- break;
5051
- case 'URL':
5052
- if( !empty( $this->url )) {
5053
- $this->url = '';
5054
- $return = TRUE;
5055
- }
5056
- break;
5057
- default:
5058
- $reduced = '';
5059
- if( $propName != 'X-PROP' ) {
5060
- if( !isset( $this->xprop[$propName] )) return FALSE;
5061
- foreach( $this->xprop as $k => $a ) {
5062
- if(( $k != $propName ) && !empty( $a ))
5063
- $reduced[$k] = $a;
5064
- }
5065
- }
5066
- else {
5067
- if( count( $this->xprop ) <= $propix ) { unset( $this->propdelix[$propName] ); return FALSE; }
5068
- $xpropno = 0;
5069
- foreach( $this->xprop as $xpropkey => $xpropvalue ) {
5070
- if( $propix != $xpropno )
5071
- $reduced[$xpropkey] = $xpropvalue;
5072
- $xpropno++;
5073
- }
5074
- }
5075
- $this->xprop = $reduced;
5076
- if( empty( $this->xprop )) {
5077
- unset( $this->propdelix[$propName] );
5078
- return FALSE;
5079
- }
5080
- return TRUE;
5081
- }
5082
- return $return;
5083
- }
5084
- /*********************************************************************************/
5085
- /**
5086
- * delete component property value, fixing components with multiple occurencies
5087
- *
5088
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
5089
- * @since 2.8.8 - 2011-03-15
5090
- * @param array $multiprop, reference to a component property
5091
- * @param int $propix, reference to removal counter
5092
- * @return bool TRUE
5093
- */
5094
- function deletePropertyM( & $multiprop, & $propix ) {
5095
- if( isset( $multiprop[$propix] ))
5096
- unset( $multiprop[$propix] );
5097
- if( empty( $multiprop )) {
5098
- $multiprop = '';
5099
- unset( $propix );
5100
- return FALSE;
5101
- }
5102
- else
5103
- return TRUE;
5104
- }
5105
- /**
5106
- * get component property value/params
5107
- *
5108
- * if property has multiply values, consequtive function calls are needed
5109
- *
5110
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
5111
- * @since 2.9.3 - 2011-05-18
5112
- * @param string $propName, optional
5113
- * @param int @propix, optional, if specific property is wanted in case of multiply occurences
5114
- * @param bool $inclParam=FALSE
5115
- * @param bool $specform=FALSE
5116
- * @return mixed
5117
- */
5118
- function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE, $specform=FALSE ) {
5119
- if( $this->_notExistProp( $propName )) return FALSE;
5120
- $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
5121
- if( in_array( $propName, array( 'ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION', 'EXDATE', 'EXRULE',
5122
- 'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME', 'X-PROP' ))) {
5123
- if( !$propix )
5124
- $propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1;
5125
- $this->propix[$propName] = --$propix;
5126
- }
5127
- switch( $propName ) {
5128
- case 'ACTION':
5129
- if( !empty( $this->action['value'] )) return ( $inclParam ) ? $this->action : $this->action['value'];
5130
- break;
5131
- case 'ATTACH':
5132
- while( is_array( $this->attach ) && !isset( $this->attach[$propix] ) && ( 0 < count( $this->attach )) && ( $propix < end( array_keys( $this->attach ))))
5133
- $propix++;
5134
- if( !isset( $this->attach[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
5135
- return ( $inclParam ) ? $this->attach[$propix] : $this->attach[$propix]['value'];
5136
- break;
5137
- case 'ATTENDEE':
5138
- while( is_array( $this->attendee ) && !isset( $this->attendee[$propix] ) && ( 0 < count( $this->attendee )) && ( $propix < end( array_keys( $this->attendee ))))
5139
- $propix++;
5140
- if( !isset( $this->attendee[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
5141
- return ( $inclParam ) ? $this->attendee[$propix] : $this->attendee[$propix]['value'];
5142
- break;
5143
- case 'CATEGORIES':
5144
- while( is_array( $this->categories ) && !isset( $this->categories[$propix] ) && ( 0 < count( $this->categories )) && ( $propix < end( array_keys( $this->categories ))))
5145
- $propix++;
5146
- if( !isset( $this->categories[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
5147
- return ( $inclParam ) ? $this->categories[$propix] : $this->categories[$propix]['value'];
5148
- break;
5149
- case 'CLASS':
5150
- if( !empty( $this->class['value'] )) return ( $inclParam ) ? $this->class : $this->class['value'];
5151
- break;
5152
- case 'COMMENT':
5153
- while( is_array( $this->comment ) && !isset( $this->comment[$propix] ) && ( 0 < count( $this->comment )) && ( $propix < end( array_keys( $this->comment ))))
5154
- $propix++;
5155
- if( !isset( $this->comment[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
5156
- return ( $inclParam ) ? $this->comment[$propix] : $this->comment[$propix]['value'];
5157
- break;
5158
- case 'COMPLETED':
5159
- if( !empty( $this->completed['value'] )) return ( $inclParam ) ? $this->completed : $this->completed['value'];
5160
- break;
5161
- case 'CONTACT':
5162
- while( is_array( $this->contact ) && !isset( $this->contact[$propix] ) && ( 0 < count( $this->contact )) && ( $propix < end( array_keys( $this->contact ))))
5163
- $propix++;
5164
- if( !isset( $this->contact[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
5165
- return ( $inclParam ) ? $this->contact[$propix] : $this->contact[$propix]['value'];
5166
- break;
5167
- case 'CREATED':
5168
- if( !empty( $this->created['value'] )) return ( $inclParam ) ? $this->created : $this->created['value'];
5169
- break;
5170
- case 'DESCRIPTION':
5171
- while( is_array( $this->description ) && !isset( $this->description[$propix] ) && ( 0 < count( $this->description )) && ( $propix < end( array_keys( $this->description ))))
5172
- $propix++;
5173
- if( !isset( $this->description[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
5174
- return ( $inclParam ) ? $this->description[$propix] : $this->description[$propix]['value'];
5175
- break;
5176
- case 'DTEND':
5177
- if( !empty( $this->dtend['value'] )) return ( $inclParam ) ? $this->dtend : $this->dtend['value'];
5178
- break;
5179
- case 'DTSTAMP':
5180
- if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
5181
- return;
5182
- if( !isset( $this->dtstamp['value'] ))
5183
- $this->_makeDtstamp();
5184
- return ( $inclParam ) ? $this->dtstamp : $this->dtstamp['value'];
5185
- break;
5186
- case 'DTSTART':
5187
- if( !empty( $this->dtstart['value'] )) return ( $inclParam ) ? $this->dtstart : $this->dtstart['value'];
5188
- break;
5189
- case 'DUE':
5190
- if( !empty( $this->due['value'] )) return ( $inclParam ) ? $this->due : $this->due['value'];
5191
- break;
5192
- case 'DURATION':
5193
- if( !isset( $this->duration['value'] )) return FALSE;
5194
- $value = ( $specform && isset( $this->dtstart['value'] ) && isset( $this->duration['value'] )) ? iCalUtilityFunctions::_duration2date( $this->dtstart['value'], $this->duration['value'] ) : $this->duration['value'];
5195
- return ( $inclParam ) ? array( 'value' => $value, 'params' => $this->duration['params'] ) : $value;
5196
- break;
5197
- case 'EXDATE':
5198
- while( is_array( $this->exdate ) && !isset( $this->exdate[$propix] ) && ( 0 < count( $this->exdate )) && ( $propix < end( array_keys( $this->exdate ))))
5199
- $propix++;
5200
- if( !isset( $this->exdate[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
5201
- return ( $inclParam ) ? $this->exdate[$propix] : $this->exdate[$propix]['value'];
5202
- break;
5203
- case 'EXRULE':
5204
- while( is_array( $this->exrule ) && !isset( $this->exrule[$propix] ) && ( 0 < count( $this->exrule )) && ( $propix < end( array_keys( $this->exrule ))))
5205
- $propix++;
5206
- if( !isset( $this->exrule[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
5207
- return ( $inclParam ) ? $this->exrule[$propix] : $this->exrule[$propix]['value'];
5208
- break;
5209
- case 'FREEBUSY':
5210
- while( is_array( $this->freebusy ) && !isset( $this->freebusy[$propix] ) && ( 0 < count( $this->freebusy )) && ( $propix < end( array_keys( $this->freebusy ))))
5211
- $propix++;
5212
- if( !isset( $this->freebusy[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
5213
- return ( $inclParam ) ? $this->freebusy[$propix] : $this->freebusy[$propix]['value'];
5214
- break;
5215
- case 'GEO':
5216
- if( !empty( $this->geo['value'] )) return ( $inclParam ) ? $this->geo : $this->geo['value'];
5217
- break;
5218
- case 'LAST-MODIFIED':
5219
- if( !empty( $this->lastmodified['value'] )) return ( $inclParam ) ? $this->lastmodified : $this->lastmodified['value'];
5220
- break;
5221
- case 'LOCATION':
5222
- if( !empty( $this->location['value'] )) return ( $inclParam ) ? $this->location : $this->location['value'];
5223
- break;
5224
- case 'ORGANIZER':
5225
- if( !empty( $this->organizer['value'] )) return ( $inclParam ) ? $this->organizer : $this->organizer['value'];
5226
- break;
5227
- case 'PERCENT-COMPLETE':
5228
- if( !empty( $this->percentcomplete['value'] ) || ( isset( $this->percentcomplete['value'] ) && ( '0' == $this->percentcomplete['value'] ))) return ( $inclParam ) ? $this->percentcomplete : $this->percentcomplete['value'];
5229
- break;
5230
- case 'PRIORITY':
5231
- if( !empty( $this->priority['value'] ) || ( isset( $this->priority['value'] ) && ('0' == $this->priority['value'] ))) return ( $inclParam ) ? $this->priority : $this->priority['value'];
5232
- break;
5233
- case 'RDATE':
5234
- while( is_array( $this->rdate ) && !isset( $this->rdate[$propix] ) && ( 0 < count( $this->rdate )) && ( $propix < end( array_keys( $this->rdate ))))
5235
- $propix++;
5236
- if( !isset( $this->rdate[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
5237
- return ( $inclParam ) ? $this->rdate[$propix] : $this->rdate[$propix]['value'];
5238
- break;
5239
- case 'RECURRENCE-ID':
5240
- if( !empty( $this->recurrenceid['value'] )) return ( $inclParam ) ? $this->recurrenceid : $this->recurrenceid['value'];
5241
- break;
5242
- case 'RELATED-TO':
5243
- while( is_array( $this->relatedto ) && !isset( $this->relatedto[$propix] ) && ( 0 < count( $this->relatedto )) && ( $propix < end( array_keys( $this->relatedto ))))
5244
- $propix++;
5245
- if( !isset( $this->relatedto[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
5246
- return ( $inclParam ) ? $this->relatedto[$propix] : $this->relatedto[$propix]['value'];
5247
- break;
5248
- case 'REPEAT':
5249
- if( !empty( $this->repeat['value'] ) || ( isset( $this->repeat['value'] ) && ( '0' == $this->repeat['value'] ))) return ( $inclParam ) ? $this->repeat : $this->repeat['value'];
5250
- break;
5251
- case 'REQUEST-STATUS':
5252
- while( is_array( $this->requeststatus ) && !isset( $this->requeststatus[$propix] ) && ( 0 < count( $this->requeststatus )) && ( $propix < end( array_keys( $this->requeststatus ))))
5253
- $propix++;
5254
- if( !isset( $this->requeststatus[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
5255
- return ( $inclParam ) ? $this->requeststatus[$propix] : $this->requeststatus[$propix]['value'];
5256
- break;
5257
- case 'RESOURCES':
5258
- while( is_array( $this->resources ) && !isset( $this->resources[$propix] ) && ( 0 < count( $this->resources )) && ( $propix < end( array_keys( $this->resources ))))
5259
- $propix++;
5260
- if( !isset( $this->resources[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
5261
- return ( $inclParam ) ? $this->resources[$propix] : $this->resources[$propix]['value'];
5262
- break;
5263
- case 'RRULE':
5264
- while( is_array( $this->rrule ) && !isset( $this->rrule[$propix] ) && ( 0 < count( $this->rrule )) && ( $propix < end( array_keys( $this->rrule ))))
5265
- $propix++;
5266
- if( !isset( $this->rrule[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
5267
- return ( $inclParam ) ? $this->rrule[$propix] : $this->rrule[$propix]['value'];
5268
- break;
5269
- case 'SEQUENCE':
5270
- if( isset( $this->sequence['value'] ) && ( isset( $this->sequence['value'] ) && ( '0' <= $this->sequence['value'] ))) return ( $inclParam ) ? $this->sequence : $this->sequence['value'];
5271
- break;
5272
- case 'STATUS':
5273
- if( !empty( $this->status['value'] )) return ( $inclParam ) ? $this->status : $this->status['value'];
5274
- break;
5275
- case 'SUMMARY':
5276
- if( !empty( $this->summary['value'] )) return ( $inclParam ) ? $this->summary : $this->summary['value'];
5277
- break;
5278
- case 'TRANSP':
5279
- if( !empty( $this->transp['value'] )) return ( $inclParam ) ? $this->transp : $this->transp['value'];
5280
- break;
5281
- case 'TRIGGER':
5282
- if( !empty( $this->trigger['value'] )) return ( $inclParam ) ? $this->trigger : $this->trigger['value'];
5283
- break;
5284
- case 'TZID':
5285
- if( !empty( $this->tzid['value'] )) return ( $inclParam ) ? $this->tzid : $this->tzid['value'];
5286
- break;
5287
- case 'TZNAME':
5288
- while( is_array( $this->tzname ) && !isset( $this->tzname[$propix] ) && ( 0 < count( $this->tzname )) && ( $propix < end( array_keys( $this->tzname ))))
5289
- $propix++;
5290
- if( !isset( $this->tzname[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
5291
- return ( $inclParam ) ? $this->tzname[$propix] : $this->tzname[$propix]['value'];
5292
- break;
5293
- case 'TZOFFSETFROM':
5294
- if( !empty( $this->tzoffsetfrom['value'] )) return ( $inclParam ) ? $this->tzoffsetfrom : $this->tzoffsetfrom['value'];
5295
- break;
5296
- case 'TZOFFSETTO':
5297
- if( !empty( $this->tzoffsetto['value'] )) return ( $inclParam ) ? $this->tzoffsetto : $this->tzoffsetto['value'];
5298
- break;
5299
- case 'TZURL':
5300
- if( !empty( $this->tzurl['value'] )) return ( $inclParam ) ? $this->tzurl : $this->tzurl['value'];
5301
- break;
5302
- case 'UID':
5303
- if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
5304
- return FALSE;
5305
- if( empty( $this->uid['value'] ))
5306
- $this->_makeuid();
5307
- return ( $inclParam ) ? $this->uid : $this->uid['value'];
5308
- break;
5309
- case 'URL':
5310
- if( !empty( $this->url['value'] )) return ( $inclParam ) ? $this->url : $this->url['value'];
5311
- break;
5312
- default:
5313
- if( $propName != 'X-PROP' ) {
5314
- if( !isset( $this->xprop[$propName] )) return FALSE;
5315
- return ( $inclParam ) ? array( $propName, $this->xprop[$propName] )
5316
- : array( $propName, $this->xprop[$propName]['value'] );
5317
- }
5318
- else {
5319
- if( empty( $this->xprop )) return FALSE;
5320
- $xpropno = 0;
5321
- foreach( $this->xprop as $xpropkey => $xpropvalue ) {
5322
- if( $propix == $xpropno )
5323
- return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] )
5324
- : array( $xpropkey, $this->xprop[$xpropkey]['value'] );
5325
- else
5326
- $xpropno++;
5327
- }
5328
- return FALSE; // not found ??
5329
- }
5330
- }
5331
- return FALSE;
5332
- }
5333
- /**
5334
- * returns calendar property unique values for 'CATEGORIES', 'RESOURCES' or 'ATTENDEE' and each number of ocurrence
5335
- *
5336
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
5337
- * @since 2.8.8 - 2011-04-13
5338
- * @param string $propName
5339
- * @param array $output, incremented result array
5340
- */
5341
- function _getProperties( $propName, & $output ) {
5342
- if( !in_array( strtoupper( $propName ), array( 'ATTENDEE', 'CATEGORIES', 'RESOURCES' )))
5343
- return output;
5344
- while( FALSE !== ( $content = $this->getProperty( $propName ))) {
5345
- if( is_array( $content )) {
5346
- foreach( $content as $part ) {
5347
- if( FALSE !== strpos( $part, ',' )) {
5348
- $part = explode( ',', $part );
5349
- foreach( $part as $thePart ) {
5350
- $thePart = trim( $thePart );
5351
- if( !empty( $thePart )) {
5352
- if( !isset( $output[$thePart] ))
5353
- $output[$thePart] = 1;
5354
- else
5355
- $output[$thePart] += 1;
5356
- }
5357
- }
5358
- }
5359
- else {
5360
- $part = trim( $part );
5361
- if( !isset( $output[$part] ))
5362
- $output[$part] = 1;
5363
- else
5364
- $output[$part] += 1;
5365
- }
5366
- }
5367
- }
5368
- elseif( FALSE !== strpos( $content, ',' )) {
5369
- $content = explode( ',', $content );
5370
- foreach( $content as $thePart ) {
5371
- $thePart = trim( $thePart );
5372
- if( !empty( $thePart )) {
5373
- if( !isset( $output[$thePart] ))
5374
- $output[$thePart] = 1;
5375
- else
5376
- $output[$thePart] += 1;
5377
- }
5378
- }
5379
- }
5380
- else {
5381
- $content = trim( $content );
5382
- if( !empty( $content )) {
5383
- if( !isset( $output[$content] ))
5384
- $output[$content] = 1;
5385
- else
5386
- $output[$content] += 1;
5387
- }
5388
- }
5389
- }
5390
- ksort( $output );
5391
- return $output;
5392
- }
5393
- /**
5394
- * general component property setting
5395
- *
5396
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
5397
- * @since 2.5.1 - 2008-11-05
5398
- * @param mixed $args variable number of function arguments,
5399
- * first argument is ALWAYS component name,
5400
- * second ALWAYS component value!
5401
- * @return void
5402
- */
5403
- function setProperty() {
5404
- $numargs = func_num_args();
5405
- if( 1 > $numargs ) return FALSE;
5406
- $arglist = func_get_args();
5407
- if( $this->_notExistProp( $arglist[0] )) return FALSE;
5408
- if( !$this->getConfig( 'allowEmpty' ) && ( !isset( $arglist[1] ) || empty( $arglist[1] )))
5409
- return FALSE;
5410
- $arglist[0] = strtoupper( $arglist[0] );
5411
- for( $argix=$numargs; $argix < 12; $argix++ ) {
5412
- if( !isset( $arglist[$argix] ))
5413
- $arglist[$argix] = null;
5414
- }
5415
- switch( $arglist[0] ) {
5416
- case 'ACTION':
5417
- return $this->setAction( $arglist[1], $arglist[2] );
5418
- case 'ATTACH':
5419
- return $this->setAttach( $arglist[1], $arglist[2], $arglist[3] );
5420
- case 'ATTENDEE':
5421
- return $this->setAttendee( $arglist[1], $arglist[2], $arglist[3] );
5422
- case 'CATEGORIES':
5423
- return $this->setCategories( $arglist[1], $arglist[2], $arglist[3] );
5424
- case 'CLASS':
5425
- return $this->setClass( $arglist[1], $arglist[2] );
5426
- case 'COMMENT':
5427
- return $this->setComment( $arglist[1], $arglist[2], $arglist[3] );
5428
- case 'COMPLETED':
5429
- return $this->setCompleted( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
5430
- case 'CONTACT':
5431
- return $this->setContact( $arglist[1], $arglist[2], $arglist[3] );
5432
- case 'CREATED':
5433
- return $this->setCreated( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
5434
- case 'DESCRIPTION':
5435
- return $this->setDescription( $arglist[1], $arglist[2], $arglist[3] );
5436
- case 'DTEND':
5437
- return $this->setDtend( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
5438
- case 'DTSTAMP':
5439
- return $this->setDtstamp( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
5440
- case 'DTSTART':
5441
- return $this->setDtstart( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
5442
- case 'DUE':
5443
- return $this->setDue( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
5444
- case 'DURATION':
5445
- return $this->setDuration( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6] );
5446
- case 'EXDATE':
5447
- return $this->setExdate( $arglist[1], $arglist[2], $arglist[3] );
5448
- case 'EXRULE':
5449
- return $this->setExrule( $arglist[1], $arglist[2], $arglist[3] );
5450
- case 'FREEBUSY':
5451
- return $this->setFreebusy( $arglist[1], $arglist[2], $arglist[3], $arglist[4] );
5452
- case 'GEO':
5453
- return $this->setGeo( $arglist[1], $arglist[2], $arglist[3] );
5454
- case 'LAST-MODIFIED':
5455
- return $this->setLastModified( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
5456
- case 'LOCATION':
5457
- return $this->setLocation( $arglist[1], $arglist[2] );
5458
- case 'ORGANIZER':
5459
- return $this->setOrganizer( $arglist[1], $arglist[2] );
5460
- case 'PERCENT-COMPLETE':
5461
- return $this->setPercentComplete( $arglist[1], $arglist[2] );
5462
- case 'PRIORITY':
5463
- return $this->setPriority( $arglist[1], $arglist[2] );
5464
- case 'RDATE':
5465
- return $this->setRdate( $arglist[1], $arglist[2], $arglist[3] );
5466
- case 'RECURRENCE-ID':
5467
- return $this->setRecurrenceid( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
5468
- case 'RELATED-TO':
5469
- return $this->setRelatedTo( $arglist[1], $arglist[2], $arglist[3] );
5470
- case 'REPEAT':
5471
- return $this->setRepeat( $arglist[1], $arglist[2] );
5472
- case 'REQUEST-STATUS':
5473
- return $this->setRequestStatus( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5] );
5474
- case 'RESOURCES':
5475
- return $this->setResources( $arglist[1], $arglist[2], $arglist[3] );
5476
- case 'RRULE':
5477
- return $this->setRrule( $arglist[1], $arglist[2], $arglist[3] );
5478
- case 'SEQUENCE':
5479
- return $this->setSequence( $arglist[1], $arglist[2] );
5480
- case 'STATUS':
5481
- return $this->setStatus( $arglist[1], $arglist[2] );
5482
- case 'SUMMARY':
5483
- return $this->setSummary( $arglist[1], $arglist[2] );
5484
- case 'TRANSP':
5485
- return $this->setTransp( $arglist[1], $arglist[2] );
5486
- case 'TRIGGER':
5487
- return $this->setTrigger( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8], $arglist[9], $arglist[10], $arglist[11] );
5488
- case 'TZID':
5489
- return $this->setTzid( $arglist[1], $arglist[2] );
5490
- case 'TZNAME':
5491
- return $this->setTzname( $arglist[1], $arglist[2], $arglist[3] );
5492
- case 'TZOFFSETFROM':
5493
- return $this->setTzoffsetfrom( $arglist[1], $arglist[2] );
5494
- case 'TZOFFSETTO':
5495
- return $this->setTzoffsetto( $arglist[1], $arglist[2] );
5496
- case 'TZURL':
5497
- return $this->setTzurl( $arglist[1], $arglist[2] );
5498
- case 'UID':
5499
- return $this->setUid( $arglist[1], $arglist[2] );
5500
- case 'URL':
5501
- return $this->setUrl( $arglist[1], $arglist[2] );
5502
- default:
5503
- return $this->setXprop( $arglist[0], $arglist[1], $arglist[2] );
5504
- }
5505
- return FALSE;
5506
- }
5507
- /*********************************************************************************/
5508
- /**
5509
- * parse component unparsed data into properties
5510
- *
5511
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
5512
- * @since 2.8.2 - 2011-05-21
5513
- * @param mixed $unparsedtext, optional, strict rfc2445 formatted, single property string or array of strings
5514
- * @return bool FALSE if error occurs during parsing
5515
- *
5516
- */
5517
- function parse( $unparsedtext=null ) {
5518
- if( !empty( $unparsedtext )) {
5519
- $nl = $this->getConfig( 'nl' );
5520
- if( is_array( $unparsedtext ))
5521
- $unparsedtext = implode( '\n'.$nl, $unparsedtext );
5522
- /* fix line folding */
5523
- $eolchars = array( "\r\n", "\n\r", "\n", "\r" ); // check all line endings
5524
- $EOLmark = FALSE;
5525
- foreach( $eolchars as $eolchar ) {
5526
- if( !$EOLmark && ( FALSE !== strpos( $unparsedtext, $eolchar ))) {
5527
- $unparsedtext = str_replace( $eolchar." ", '', $unparsedtext );
5528
- $unparsedtext = str_replace( $eolchar."\t", '', $unparsedtext );
5529
- if( $eolchar != $nl )
5530
- $unparsedtext = str_replace( $eolchar, $nl, $unparsedtext );
5531
- $EOLmark = TRUE;
5532
- }
5533
- }
5534
- $tmp = explode( $nl, $unparsedtext );
5535
- $unparsedtext = array();
5536
- foreach( $tmp as $tmpr )
5537
- if( !empty( $tmpr ))
5538
- $unparsedtext[] = $tmpr;
5539
- }
5540
- elseif( !isset( $this->unparsed ))
5541
- $unparsedtext = array();
5542
- else
5543
- $unparsedtext = $this->unparsed;
5544
- $this->unparsed = array();
5545
- $comp = & $this;
5546
- $config = $this->getConfig();
5547
- foreach ( $unparsedtext as $line ) {
5548
- // echo $comp->objName.": $line<br />"; // test ###
5549
- if( in_array( strtoupper( substr( $line, 0, 6 )), array( 'END:VA', 'END:ST', 'END:DA' )))
5550
- $this->components[] = $comp->copy();
5551
- elseif( 'END:' == strtoupper( substr( $line, 0, 4 )))
5552
- break;
5553
- elseif( 'BEGIN:VALARM' == strtoupper( substr( $line, 0, 12 )))
5554
- $comp = new valarm( $config);
5555
- elseif( 'BEGIN:STANDARD' == strtoupper( substr( $line, 0, 14 )))
5556
- $comp = new vtimezone( 'standard', $config );
5557
- elseif( 'BEGIN:DAYLIGHT' == strtoupper( substr( $line, 0, 14 )))
5558
- $comp = new vtimezone( 'daylight', $config );
5559
- elseif( 'BEGIN:' == strtoupper( substr( $line, 0, 6 )))
5560
- continue;
5561
- else {
5562
- $comp->unparsed[] = $line;
5563
- // echo $comp->objName.": $line<br />\n"; // test ###
5564
- }
5565
- }
5566
- unset( $config );
5567
- // echo $this->objName.'<br />'.var_export( $this->unparsed, TRUE )."<br />\n"; // test ###
5568
- /* concatenate property values spread over several lines */
5569
- $lastix = -1;
5570
- $propnames = array( 'action', 'attach', 'attendee', 'categories', 'comment', 'completed'
5571
- , 'contact', 'class', 'created', 'description', 'dtend', 'dtstart'
5572
- , 'dtstamp', 'due', 'duration', 'exdate', 'exrule', 'freebusy', 'geo'
5573
- , 'last-modified', 'location', 'organizer', 'percent-complete'
5574
- , 'priority', 'rdate', 'recurrence-id', 'related-to', 'repeat'
5575
- , 'request-status', 'resources', 'rrule', 'sequence', 'status'
5576
- , 'summary', 'transp', 'trigger', 'tzid', 'tzname', 'tzoffsetfrom'
5577
- , 'tzoffsetto', 'tzurl', 'uid', 'url', 'x-' );
5578
- $proprows = array();
5579
- foreach( $this->unparsed as $line ) {
5580
- $newProp = FALSE;
5581
- foreach ( $propnames as $propname ) {
5582
- if( $propname == strtolower( substr( $line, 0, strlen( $propname )))) {
5583
- $newProp = TRUE;
5584
- break;
5585
- }
5586
- }
5587
- if( $newProp ) {
5588
- if( -1 < $lastix )
5589
- $proprows[$lastix] = $proprows[$lastix];
5590
- $newProp = FALSE;
5591
- $lastix++;
5592
- $proprows[$lastix] = $line;
5593
- }
5594
- else
5595
- $proprows[$lastix] .= '!"#¤%&/()=?'.$line;
5596
- }
5597
- /* parse each property 'line' */
5598
- foreach( $proprows as $line ) {
5599
- $line = str_replace( '!"#¤%&/()=? ', '', $line );
5600
- $line = str_replace( '!"#¤%&/()=?', '', $line );
5601
- if( '\n' == substr( $line, -2 ))
5602
- $line = substr( $line, 0, strlen( $line ) - 2 );
5603
- /* get propname, (problem with x-properties, otherwise in previous loop) */
5604
- $cix = $propname = null;
5605
- for( $cix=0, $clen = strlen( $line ); $cix < $clen; $cix++ ) {
5606
- if( in_array( $line[$cix], array( ':', ';' )))
5607
- break;
5608
- else {
5609
- $propname .= $line[$cix];
5610
- }
5611
- }
5612
- if(( 'x-' == substr( $propname, 0, 2 )) || ( 'X-' == substr( $propname, 0, 2 ))) {
5613
- $propname2 = $propname;
5614
- $propname = 'X-';
5615
- }
5616
- /* rest of the line is opt.params and value */
5617
- $line = substr( $line, $cix );
5618
- /* separate attributes from value */
5619
- $attr = array();
5620
- $attrix = -1;
5621
- $clen = strlen( $line );
5622
- for( $cix=0; $cix < $clen; $cix++ ) {
5623
- if(( ':' == $line[$cix] ) &&
5624
- ( '://' != substr( $line, $cix, 3 )) &&
5625
- ( !in_array( strtolower( substr( $line, $cix - 3, 4 )), array( 'fax:', 'cid:', 'sms:', 'tel:', 'urn:' ))) &&
5626
- ( !in_array( strtolower( substr( $line, $cix - 4, 5 )), array( 'crid:', 'news:', 'pres:' ))) &&
5627
- ( 'mailto:' != strtolower( substr( $line, $cix - 6, 7 )))) {
5628
- $attrEnd = TRUE;
5629
- if(( $cix < ( $clen - 4 )) &&
5630
- ctype_digit( substr( $line, $cix+1, 4 ))) { // an URI with a (4pos) portnr??
5631
- for( $c2ix = $cix; 3 < $c2ix; $c2ix-- ) {
5632
- if( '://' == substr( $line, $c2ix - 2, 3 )) {
5633
- $attrEnd = FALSE;
5634
- break; // an URI with a portnr!!
5635
- }
5636
- }
5637
- }
5638
- if( $attrEnd) {
5639
- $line = substr( $line, $cix + 1 );
5640
- break;
5641
- }
5642
- }
5643
- if( ';' == $line[$cix] )
5644
- $attr[++$attrix] = null;
5645
- else
5646
- $attr[$attrix] .= $line[$cix];
5647
- }
5648
- /* make attributes in array format */
5649
- $propattr = array();
5650
- foreach( $attr as $attribute ) {
5651
- $attrsplit = explode( '=', $attribute, 2 );
5652
- if( 1 < count( $attrsplit ))
5653
- $propattr[$attrsplit[0]] = $attrsplit[1];
5654
- else
5655
- $propattr[] = $attribute;
5656
- }
5657
- /* call setProperty( $propname.. . */
5658
- switch( strtoupper( $propname )) {
5659
- case 'ATTENDEE':
5660
- foreach( $propattr as $pix => $attr ) {
5661
- $attr2 = explode( ',', $attr );
5662
- if( 1 < count( $attr2 ))
5663
- $propattr[$pix] = $attr2;
5664
- }
5665
- $this->setProperty( $propname, $line, $propattr );
5666
- break;
5667
- case 'CATEGORIES':
5668
- case 'RESOURCES':
5669
- if( FALSE !== strpos( $line, ',' )) {
5670
- $content = explode( ',', $line );
5671
- $clen = count( $content );
5672
- for( $cix = 0; $cix < $clen; $cix++ ) {
5673
- if( "\\" == substr($content[$cix], -1)) {
5674
- $content[$cix] .= ','.$content[$cix + 1];
5675
- unset($content[$cix + 1]);
5676
- $cix++;
5677
- }
5678
- }
5679
- if( 1 < count( $content )) {
5680
- $content = array_values( $content );
5681
- foreach( $content as $cix => $contentPart )
5682
- $content[$cix] = calendarComponent::_strunrep( $contentPart );
5683
- $this->setProperty( $propname, $content, $propattr );
5684
- break;
5685
- }
5686
- else
5687
- $line = reset( $content );
5688
- }
5689
- case 'X-':
5690
- $propname = ( isset( $propname2 )) ? $propname2 : $propname;
5691
- case 'COMMENT':
5692
- case 'CONTACT':
5693
- case 'DESCRIPTION':
5694
- case 'LOCATION':
5695
- case 'SUMMARY':
5696
- if( empty( $line ))
5697
- $propattr = null;
5698
- $this->setProperty( $propname, calendarComponent::_strunrep( $line ), $propattr );
5699
- unset( $propname2 );
5700
- break;
5701
- case 'REQUEST-STATUS':
5702
- $values = explode( ';', $line, 3 );
5703
- $values[1] = ( !isset( $values[1] )) ? null : calendarComponent::_strunrep( $values[1] );
5704
- $values[2] = ( !isset( $values[2] )) ? null : calendarComponent::_strunrep( $values[2] );
5705
- $this->setProperty( $propname
5706
- , $values[0] // statcode
5707
- , $values[1] // statdesc
5708
- , $values[2] // extdata
5709
- , $propattr );
5710
- break;
5711
- case 'FREEBUSY':
5712
- $fbtype = ( isset( $propattr['FBTYPE'] )) ? $propattr['FBTYPE'] : ''; // force setting default, if missing
5713
- unset( $propattr['FBTYPE'] );
5714
- $values = explode( ',', $line );
5715
- foreach( $values as $vix => $value ) {
5716
- $value2 = explode( '/', $value );
5717
- if( 1 < count( $value2 ))
5718
- $values[$vix] = $value2;
5719
- }
5720
- $this->setProperty( $propname, $fbtype, $values, $propattr );
5721
- break;
5722
- case 'GEO':
5723
- $value = explode( ';', $line, 2 );
5724
- if( 2 > count( $value ))
5725
- $value[1] = null;
5726
- $this->setProperty( $propname, $value[0], $value[1], $propattr );
5727
- break;
5728
- case 'EXDATE':
5729
- $values = ( !empty( $line )) ? explode( ',', $line ) : null;
5730
- $this->setProperty( $propname, $values, $propattr );
5731
- break;
5732
- case 'RDATE':
5733
- if( empty( $line )) {
5734
- $this->setProperty( $propname, $line, $propattr );
5735
- break;
5736
- }
5737
- $values = explode( ',', $line );
5738
- foreach( $values as $vix => $value ) {
5739
- $value2 = explode( '/', $value );
5740
- if( 1 < count( $value2 ))
5741
- $values[$vix] = $value2;
5742
- }
5743
- $this->setProperty( $propname, $values, $propattr );
5744
- break;
5745
- case 'EXRULE':
5746
- case 'RRULE':
5747
- $values = explode( ';', $line );
5748
- $recur = array();
5749
- foreach( $values as $value2 ) {
5750
- if( empty( $value2 ))
5751
- continue; // ;-char in ending position ???
5752
- $value3 = explode( '=', $value2, 2 );
5753
- $rulelabel = strtoupper( $value3[0] );
5754
- switch( $rulelabel ) {
5755
- case 'BYDAY': {
5756
- $value4 = explode( ',', $value3[1] );
5757
- if( 1 < count( $value4 )) {
5758
- foreach( $value4 as $v5ix => $value5 ) {
5759
- $value6 = array();
5760
- $dayno = $dayname = null;
5761
- $value5 = trim( (string) $value5 );
5762
- if(( ctype_alpha( substr( $value5, -1 ))) &&
5763
- ( ctype_alpha( substr( $value5, -2, 1 )))) {
5764
- $dayname = substr( $value5, -2, 2 );
5765
- if( 2 < strlen( $value5 ))
5766
- $dayno = substr( $value5, 0, ( strlen( $value5 ) - 2 ));
5767
- }
5768
- if( $dayno )
5769
- $value6[] = $dayno;
5770
- if( $dayname )
5771
- $value6['DAY'] = $dayname;
5772
- $value4[$v5ix] = $value6;
5773
- }
5774
- }
5775
- else {
5776
- $value4 = array();
5777
- $dayno = $dayname = null;
5778
- $value5 = trim( (string) $value3[1] );
5779
- if(( ctype_alpha( substr( $value5, -1 ))) &&
5780
- ( ctype_alpha( substr( $value5, -2, 1 )))) {
5781
- $dayname = substr( $value5, -2, 2 );
5782
- if( 2 < strlen( $value5 ))
5783
- $dayno = substr( $value5, 0, ( strlen( $value5 ) - 2 ));
5784
- }
5785
- if( $dayno )
5786
- $value4[] = $dayno;
5787
- if( $dayname )
5788
- $value4['DAY'] = $dayname;
5789
- }
5790
- $recur[$rulelabel] = $value4;
5791
- break;
5792
- }
5793
- default: {
5794
- $value4 = explode( ',', $value3[1] );
5795
- if( 1 < count( $value4 ))
5796
- $value3[1] = $value4;
5797
- $recur[$rulelabel] = $value3[1];
5798
- break;
5799
- }
5800
- } // end - switch $rulelabel
5801
- } // end - foreach( $values.. .
5802
- $this->setProperty( $propname, $recur, $propattr );
5803
- break;
5804
- case 'ACTION':
5805
- case 'CLASSIFICATION':
5806
- case 'STATUS':
5807
- case 'TRANSP':
5808
- case 'UID':
5809
- case 'TZID':
5810
- case 'RELATED-TO':
5811
- case 'TZNAME':
5812
- $line = calendarComponent::_strunrep( $line );
5813
- default:
5814
- $this->setProperty( $propname, $line, $propattr );
5815
- break;
5816
- } // end switch( $propname.. .
5817
- } // end - foreach( $proprows.. .
5818
- unset( $unparsedtext, $this->unparsed, $proprows );
5819
- if( isset( $this->components ) && is_array( $this->components ) && ( 0 < count( $this->components ))) {
5820
- $ckeys = array_keys( $this->components );
5821
- foreach( $ckeys as $ckey ) {
5822
- if( !empty( $this->components[$ckey] ) && !empty( $this->components[$ckey]->unparsed )) {
5823
- $this->components[$ckey]->parse();
5824
- }
5825
- }
5826
- }
5827
- return TRUE;
5828
- }
5829
- /*********************************************************************************/
5830
- /*********************************************************************************/
5831
- /**
5832
- * return a copy of this component
5833
- *
5834
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
5835
- * @since 2.8.8 - 2011-03-15
5836
- * @return object
5837
- */
5838
- function copy() {
5839
- $serialized_contents = serialize( $this );
5840
- $copy = unserialize( $serialized_contents );
5841
- return $copy;
5842
- }
5843
- /*********************************************************************************/
5844
- /*********************************************************************************/
5845
- /**
5846
- * delete calendar subcomponent from component container
5847
- *
5848
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
5849
- * @since 2.8.8 - 2011-03-15
5850
- * @param mixed $arg1 ordno / component type / component uid
5851
- * @param mixed $arg2 optional, ordno if arg1 = component type
5852
- * @return void
5853
- */
5854
- function deleteComponent( $arg1, $arg2=FALSE ) {
5855
- if( !isset( $this->components )) return FALSE;
5856
- $argType = $index = null;
5857
- if ( ctype_digit( (string) $arg1 )) {
5858
- $argType = 'INDEX';
5859
- $index = (int) $arg1 - 1;
5860
- }
5861
- elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
5862
- $argType = strtolower( $arg1 );
5863
- $index = ( !empty( $arg2 ) && ctype_digit( (string) $arg2 )) ? (( int ) $arg2 - 1 ) : 0;
5864
- }
5865
- $cix2dC = 0;
5866
- foreach ( $this->components as $cix => $component) {
5867
- if( empty( $component )) continue;
5868
- if(( 'INDEX' == $argType ) && ( $index == $cix )) {
5869
- unset( $this->components[$cix] );
5870
- return TRUE;
5871
- }
5872
- elseif( $argType == $component->objName ) {
5873
- if( $index == $cix2dC ) {
5874
- unset( $this->components[$cix] );
5875
- return TRUE;
5876
- }
5877
- $cix2dC++;
5878
- }
5879
- elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) {
5880
- unset( $this->components[$cix] );
5881
- return TRUE;
5882
- }
5883
- }
5884
- return FALSE;
5885
- }
5886
- /**
5887
- * get calendar component subcomponent from component container
5888
- *
5889
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
5890
- * @since 2.8.8 - 2011-03-15
5891
- * @param mixed $arg1 optional, ordno/component type/ component uid
5892
- * @param mixed $arg2 optional, ordno if arg1 = component type
5893
- * @return object
5894
- */
5895
- function getComponent ( $arg1=FALSE, $arg2=FALSE ) {
5896
- if( !isset( $this->components )) return FALSE;
5897
- $index = $argType = null;
5898
- if ( !$arg1 ) {
5899
- $argType = 'INDEX';
5900
- $index = $this->compix['INDEX'] =
5901
- ( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1;
5902
- }
5903
- elseif ( ctype_digit( (string) $arg1 )) {
5904
- $argType = 'INDEX';
5905
- $index = (int) $arg1;
5906
- unset( $this->compix );
5907
- }
5908
- elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
5909
- unset( $this->compix['INDEX'] );
5910
- $argType = strtolower( $arg1 );
5911
- if( !$arg2 )
5912
- $index = $this->compix[$argType] = ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1;
5913
- else
5914
- $index = (int) $arg2;
5915
- }
5916
- $index -= 1;
5917
- $ckeys = array_keys( $this->components );
5918
- if( !empty( $index) && ( $index > end( $ckeys )))
5919
- return FALSE;
5920
- $cix2gC = 0;
5921
- foreach( $this->components as $cix => $component ) {
5922
- if( empty( $component )) continue;
5923
- if(( 'INDEX' == $argType ) && ( $index == $cix ))
5924
- return $component->copy();
5925
- elseif( $argType == $component->objName ) {
5926
- if( $index == $cix2gC )
5927
- return $component->copy();
5928
- $cix2gC++;
5929
- }
5930
- elseif( !$argType && ( $arg1 == $component->getProperty( 'uid' )))
5931
- return $component->copy();
5932
- }
5933
- /* not found.. . */
5934
- unset( $this->compix );
5935
- return false;
5936
- }
5937
- /**
5938
- * add calendar component as subcomponent to container for subcomponents
5939
- *
5940
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
5941
- * @since 1.x.x - 2007-04-24
5942
- * @param object $component calendar component
5943
- * @return void
5944
- */
5945
- function addSubComponent ( $component ) {
5946
- $this->setComponent( $component );
5947
- }
5948
- /**
5949
- * create new calendar component subcomponent, already included within component
5950
- *
5951
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
5952
- * @since 2.6.33 - 2011-01-03
5953
- * @param string $compType subcomponent type
5954
- * @return object (reference)
5955
- */
5956
- function & newComponent( $compType ) {
5957
- $config = $this->getConfig();
5958
- $keys = array_keys( $this->components );
5959
- $ix = end( $keys) + 1;
5960
- switch( strtoupper( $compType )) {
5961
- case 'ALARM':
5962
- case 'VALARM':
5963
- $this->components[$ix] = new valarm( $config );
5964
- break;
5965
- case 'STANDARD':
5966
- array_unshift( $this->components, new vtimezone( 'STANDARD', $config ));
5967
- $ix = 0;
5968
- break;
5969
- case 'DAYLIGHT':
5970
- $this->components[$ix] = new vtimezone( 'DAYLIGHT', $config );
5971
- break;
5972
- default:
5973
- return FALSE;
5974
- }
5975
- return $this->components[$ix];
5976
- }
5977
- /**
5978
- * add calendar component as subcomponent to container for subcomponents
5979
- *
5980
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
5981
- * @since 2.8.8 - 2011-03-15
5982
- * @param object $component calendar component
5983
- * @param mixed $arg1 optional, ordno/component type/ component uid
5984
- * @param mixed $arg2 optional, ordno if arg1 = component type
5985
- * @return bool
5986
- */
5987
- function setComponent( $component, $arg1=FALSE, $arg2=FALSE ) {
5988
- if( !isset( $this->components )) return FALSE;
5989
- $component->setConfig( $this->getConfig(), FALSE, TRUE );
5990
- if( !in_array( $component->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) {
5991
- /* make sure dtstamp and uid is set */
5992
- $dummy = $component->getProperty( 'dtstamp' );
5993
- $dummy = $component->getProperty( 'uid' );
5994
- }
5995
- if( !$arg1 ) { // plain insert, last in chain
5996
- $this->components[] = $component->copy();
5997
- return TRUE;
5998
- }
5999
- $argType = $index = null;
6000
- if ( ctype_digit( (string) $arg1 )) { // index insert/replace
6001
- $argType = 'INDEX';
6002
- $index = (int) $arg1 - 1;
6003
- }
6004
- elseif( in_array( strtolower( $arg1 ), array( 'vevent', 'vtodo', 'vjournal', 'vfreebusy', 'valarm', 'vtimezone' ))) {
6005
- $argType = strtolower( $arg1 );
6006
- $index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0;
6007
- }
6008
- // else if arg1 is set, arg1 must be an UID
6009
- $cix2sC = 0;
6010
- foreach ( $this->components as $cix => $component2 ) {
6011
- if( empty( $component2 )) continue;
6012
- if(( 'INDEX' == $argType ) && ( $index == $cix )) { // index insert/replace
6013
- $this->components[$cix] = $component->copy();
6014
- return TRUE;
6015
- }
6016
- elseif( $argType == $component2->objName ) { // component Type index insert/replace
6017
- if( $index == $cix2sC ) {
6018
- $this->components[$cix] = $component->copy();
6019
- return TRUE;
6020
- }
6021
- $cix2sC++;
6022
- }
6023
- elseif( !$argType && ( $arg1 == $component2->getProperty( 'uid' ))) { // UID insert/replace
6024
- $this->components[$cix] = $component->copy();
6025
- return TRUE;
6026
- }
6027
- }
6028
- /* arg1=index and not found.. . insert at index .. .*/
6029
- if( 'INDEX' == $argType ) {
6030
- $this->components[$index] = $component->copy();
6031
- ksort( $this->components, SORT_NUMERIC );
6032
- }
6033
- else /* not found.. . insert last in chain anyway .. .*/
6034
- $this->components[] = $component->copy();
6035
- return TRUE;
6036
- }
6037
- /**
6038
- * creates formatted output for subcomponents
6039
- *
6040
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6041
- * @since 2.6.27 - 2010-12-12
6042
- * @return string
6043
- */
6044
- function createSubComponent() {
6045
- $output = null;
6046
- foreach( $this->components as $component ) {
6047
- if( empty( $component )) continue;
6048
- $component->setConfig( $this->getConfig(), FALSE, TRUE );
6049
- $output .= $component->createComponent( $this->xcaldecl );
6050
- }
6051
- return $output;
6052
- }
6053
- /********************************************************************************/
6054
- /**
6055
- * break lines at pos 75
6056
- *
6057
- * Lines of text SHOULD NOT be longer than 75 octets, excluding the line
6058
- * break. Long content lines SHOULD be split into a multiple line
6059
- * representations using a line "folding" technique. That is, a long
6060
- * line can be split between any two characters by inserting a CRLF
6061
- * immediately followed by a single linear white space character (i.e.,
6062
- * SPACE, US-ASCII decimal 32 or HTAB, US-ASCII decimal 9). Any sequence
6063
- * of CRLF followed immediately by a single linear white space character
6064
- * is ignored (i.e., removed) when processing the content type.
6065
- *
6066
- * Edited 2007-08-26 by Anders Litzell, anders@litzell.se to fix bug where
6067
- * the reserved expression "\n" in the arg $string could be broken up by the
6068
- * folding of lines, causing ambiguity in the return string.
6069
- * Fix uses var $breakAtChar=75 and breaks the line at $breakAtChar-1 if need be.
6070
- *
6071
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6072
- * @since 2.6.13 - 2010-12-06
6073
- * @param string $value
6074
- * @return string
6075
- */
6076
- function _size75( $string ) {
6077
- $tmp = $string;
6078
- $string = null;
6079
- /* if PHP is config with mb_string.. . */
6080
- if( defined( MB_OVERLOAD_STRING )) {
6081
- $strlen = mb_strlen( $tmp );
6082
- while( $strlen > 75 ) {
6083
- $breakAtChar = 75;
6084
- if( substr( $tmp, ( $breakAtChar - 1 ), strlen( '\n' )) == '\n' )
6085
- $breakAtChar = $breakAtChar - 1;
6086
- $string .= mb_substr( $tmp, 0, $breakAtChar );
6087
- if( '\n' == substr( $string, ( 0 - strlen( '\n' ))))
6088
- $string = substr( $string, 0, ( strlen( $string ) - strlen( '\n' )));
6089
- if( $this->nl != mb_substr( $string, ( 0 - strlen( $this->nl ))))
6090
- $string .= $this->nl;
6091
- $tmp = ' '.mb_substr( $tmp, $breakAtChar );
6092
- $strlen = mb_strlen( $tmp );
6093
- } // end while
6094
- if( 0 < $strlen ) {
6095
- $string .= $tmp; // the rest
6096
- if( '\n' == substr( $string, ( 0 - strlen( '\n' ))))
6097
- $string = substr( $string, 0, ( strlen( $string ) - strlen( '\n' )));
6098
- if( $this->nl != mb_substr( $string, ( 0 - strlen( $this->nl ))))
6099
- $string .= $this->nl;
6100
- }
6101
- return $string;
6102
- }
6103
- /* if PHP is not config with mb_string.. . */
6104
- $eolcharlen = strlen( '\n' );
6105
- while( TRUE ) {
6106
- $bytecnt = strlen( $tmp );
6107
- $charCnt = $ix = 0;
6108
- for( $ix = 0; $ix < $bytecnt; $ix++ ) {
6109
- if(( 73 < $charCnt ) && ( '\n' == substr( $tmp, $ix, $eolcharlen ))) {
6110
- $ix += $eolcharlen;
6111
- break; // break when '\n' and eol
6112
- }
6113
- elseif( 74 < $charCnt )
6114
- break; // always break for-loop here
6115
- else {
6116
- $byte = ord( $tmp[$ix] );
6117
- if ($byte <= 127) { // add a one byte character
6118
- $string .= substr( $tmp, $ix, 1 );
6119
- $charCnt += 1;
6120
- }
6121
- else if ($byte >= 194 && $byte <= 223) { // start byte in two byte character
6122
- $string .= substr( $tmp, $ix, 2 ); // add a two bytes character
6123
- $charCnt += 1;
6124
- }
6125
- else if ($byte >= 224 && $byte <= 239) { // start byte in three bytes character
6126
- $string .= substr( $tmp, $ix, 3 ); // add a three bytes character
6127
- $charCnt += 1;
6128
- }
6129
- else if ($byte >= 240 && $byte <= 244) { // start byte in four bytes character
6130
- $string .= substr( $tmp, $ix, 4 ); // add a four bytes character
6131
- $charCnt += 1;
6132
- }
6133
- }
6134
- } // end for
6135
- if( '\n' == substr( $string, ( 0 - strlen( '\n' ))))
6136
- $string = substr( $string, 0, ( strlen( $string ) - strlen( '\n' )));
6137
- if( $this->nl != substr( $string, ( 0 - strlen( $this->nl ))))
6138
- $string .= $this->nl;
6139
- $tmp = substr( $tmp, $ix );
6140
- if( empty( $tmp ))
6141
- break; // while-loop breakes here
6142
- else
6143
- $tmp = ' '.$tmp;
6144
- } // end while
6145
- if( !empty( $tmp )) {
6146
- if( '\n' == substr( $string, ( 0 - strlen( '\n' ))))
6147
- $string = substr( $string, 0, ( strlen( $string ) - strlen( '\n' ))).$this->nl;
6148
- if( $this->nl != substr( $string, ( 0 - strlen( $this->nl ))))
6149
- $string .= $this->nl;
6150
- }
6151
- return $string;
6152
- }
6153
- /**
6154
- * special characters management output
6155
- *
6156
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6157
- * @since 2.6.15 - 2010-09-24
6158
- * @param string $string
6159
- * @return string
6160
- */
6161
- function _strrep( $string ) {
6162
- switch( $this->format ) {
6163
- case 'xcal':
6164
- $string = str_replace( '\n', $this->nl, $string);
6165
- $string = htmlspecialchars( strip_tags( stripslashes( urldecode ( $string ))));
6166
- break;
6167
- default:
6168
- $pos = 0;
6169
- $specChars = array( 'n', 'N', 'r', ',', ';' );
6170
- while( $pos <= strlen( $string )) {
6171
- $pos = strpos( $string, "\\", $pos );
6172
- if( FALSE === $pos )
6173
- break;
6174
- if( !in_array( substr( $string, $pos, 1 ), $specChars )) {
6175
- $string = substr( $string, 0, $pos )."\\".substr( $string, ( $pos + 1 ));
6176
- $pos += 1;
6177
- }
6178
- $pos += 1;
6179
- }
6180
- if( FALSE !== strpos( $string, '"' ))
6181
- $string = str_replace('"', "'", $string);
6182
- if( FALSE !== strpos( $string, ',' ))
6183
- $string = str_replace(',', '\,', $string);
6184
- if( FALSE !== strpos( $string, ';' ))
6185
- $string = str_replace(';', '\;', $string);
6186
-
6187
- if( FALSE !== strpos( $string, "\r\n" ))
6188
- $string = str_replace( "\r\n", '\n', $string);
6189
- elseif( FALSE !== strpos( $string, "\r" ))
6190
- $string = str_replace( "\r", '\n', $string);
6191
-
6192
- elseif( FALSE !== strpos( $string, "\n" ))
6193
- $string = str_replace( "\n", '\n', $string);
6194
-
6195
- if( FALSE !== strpos( $string, '\N' ))
6196
- $string = str_replace( '\N', '\n', $string);
6197
- // if( FALSE !== strpos( $string, $this->nl ))
6198
- $string = str_replace( $this->nl, '\n', $string);
6199
- break;
6200
- }
6201
- return $string;
6202
- }
6203
- /**
6204
- * special characters management input (from iCal file)
6205
- *
6206
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6207
- * @since 2.6.22 - 2010-10-17
6208
- * @param string $string
6209
- * @return string
6210
- */
6211
- static function _strunrep( $string ) {
6212
- $string = str_replace( '\\\\', '\\', $string);
6213
- $string = str_replace( '\,', ',', $string);
6214
- $string = str_replace( '\;', ';', $string);
6215
- // $string = str_replace( '\n', $this->nl, $string); // ??
6216
- return $string;
6217
- }
6218
- }
6219
- /*********************************************************************************/
6220
- /*********************************************************************************/
6221
- /**
6222
- * class for calendar component VEVENT
6223
- *
6224
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6225
- * @since 2.5.1 - 2008-10-12
6226
- */
6227
- class vevent extends calendarComponent {
6228
- var $attach;
6229
- var $attendee;
6230
- var $categories;
6231
- var $comment;
6232
- var $contact;
6233
- var $class;
6234
- var $created;
6235
- var $description;
6236
- var $dtend;
6237
- var $dtstart;
6238
- var $duration;
6239
- var $exdate;
6240
- var $exrule;
6241
- var $geo;
6242
- var $lastmodified;
6243
- var $location;
6244
- var $organizer;
6245
- var $priority;
6246
- var $rdate;
6247
- var $recurrenceid;
6248
- var $relatedto;
6249
- var $requeststatus;
6250
- var $resources;
6251
- var $rrule;
6252
- var $sequence;
6253
- var $status;
6254
- var $summary;
6255
- var $transp;
6256
- var $url;
6257
- var $xprop;
6258
- // component subcomponents container
6259
- var $components;
6260
- /**
6261
- * constructor for calendar component VEVENT object
6262
- *
6263
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6264
- * @since 2.8.2 - 2011-05-01
6265
- * @param array $config
6266
- * @return void
6267
- */
6268
- function vevent( $config = array()) {
6269
- $this->calendarComponent();
6270
-
6271
- $this->attach = '';
6272
- $this->attendee = '';
6273
- $this->categories = '';
6274
- $this->class = '';
6275
- $this->comment = '';
6276
- $this->contact = '';
6277
- $this->created = '';
6278
- $this->description = '';
6279
- $this->dtstart = '';
6280
- $this->dtend = '';
6281
- $this->duration = '';
6282
- $this->exdate = '';
6283
- $this->exrule = '';
6284
- $this->geo = '';
6285
- $this->lastmodified = '';
6286
- $this->location = '';
6287
- $this->organizer = '';
6288
- $this->priority = '';
6289
- $this->rdate = '';
6290
- $this->recurrenceid = '';
6291
- $this->relatedto = '';
6292
- $this->requeststatus = '';
6293
- $this->resources = '';
6294
- $this->rrule = '';
6295
- $this->sequence = '';
6296
- $this->status = '';
6297
- $this->summary = '';
6298
- $this->transp = '';
6299
- $this->url = '';
6300
- $this->xprop = '';
6301
-
6302
- $this->components = array();
6303
-
6304
- if( defined( 'ICAL_LANG' ) && !isset( $config['language'] ))
6305
- $config['language'] = ICAL_LANG;
6306
- if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE;
6307
- if( !isset( $config['nl'] )) $config['nl'] = "\r\n";
6308
- if( !isset( $config['format'] )) $config['format'] = 'iCal';
6309
- if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR;
6310
- $this->setConfig( $config );
6311
-
6312
- }
6313
- /**
6314
- * create formatted output for calendar component VEVENT object instance
6315
- *
6316
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6317
- * @since 2.5.1 - 2008-11-07
6318
- * @param array $xcaldecl
6319
- * @return string
6320
- */
6321
- function createComponent( &$xcaldecl ) {
6322
- $objectname = $this->_createFormat();
6323
- $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
6324
- $component .= $this->createUid();
6325
- $component .= $this->createDtstamp();
6326
- $component .= $this->createAttach();
6327
- $component .= $this->createAttendee();
6328
- $component .= $this->createCategories();
6329
- $component .= $this->createComment();
6330
- $component .= $this->createContact();
6331
- $component .= $this->createClass();
6332
- $component .= $this->createCreated();
6333
- $component .= $this->createDescription();
6334
- $component .= $this->createDtstart();
6335
- $component .= $this->createDtend();
6336
- $component .= $this->createDuration();
6337
- $component .= $this->createExdate();
6338
- $component .= $this->createExrule();
6339
- $component .= $this->createGeo();
6340
- $component .= $this->createLastModified();
6341
- $component .= $this->createLocation();
6342
- $component .= $this->createOrganizer();
6343
- $component .= $this->createPriority();
6344
- $component .= $this->createRdate();
6345
- $component .= $this->createRrule();
6346
- $component .= $this->createRelatedTo();
6347
- $component .= $this->createRequestStatus();
6348
- $component .= $this->createRecurrenceid();
6349
- $component .= $this->createResources();
6350
- $component .= $this->createSequence();
6351
- $component .= $this->createStatus();
6352
- $component .= $this->createSummary();
6353
- $component .= $this->createTransp();
6354
- $component .= $this->createUrl();
6355
- $component .= $this->createXprop();
6356
- $component .= $this->createSubComponent();
6357
- $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
6358
- if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
6359
- foreach( $this->xcaldecl as $localxcaldecl )
6360
- $xcaldecl[] = $localxcaldecl;
6361
- }
6362
- return $component;
6363
- }
6364
- }
6365
- /*********************************************************************************/
6366
- /*********************************************************************************/
6367
- /**
6368
- * class for calendar component VTODO
6369
- *
6370
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6371
- * @since 2.5.1 - 2008-10-12
6372
- */
6373
- class vtodo extends calendarComponent {
6374
- var $attach;
6375
- var $attendee;
6376
- var $categories;
6377
- var $comment;
6378
- var $completed;
6379
- var $contact;
6380
- var $class;
6381
- var $created;
6382
- var $description;
6383
- var $dtstart;
6384
- var $due;
6385
- var $duration;
6386
- var $exdate;
6387
- var $exrule;
6388
- var $geo;
6389
- var $lastmodified;
6390
- var $location;
6391
- var $organizer;
6392
- var $percentcomplete;
6393
- var $priority;
6394
- var $rdate;
6395
- var $recurrenceid;
6396
- var $relatedto;
6397
- var $requeststatus;
6398
- var $resources;
6399
- var $rrule;
6400
- var $sequence;
6401
- var $status;
6402
- var $summary;
6403
- var $url;
6404
- var $xprop;
6405
- // component subcomponents container
6406
- var $components;
6407
- /**
6408
- * constructor for calendar component VTODO object
6409
- *
6410
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6411
- * @since 2.8.2 - 2011-05-01
6412
- * @param array $config
6413
- * @return void
6414
- */
6415
- function vtodo( $config = array()) {
6416
- $this->calendarComponent();
6417
-
6418
- $this->attach = '';
6419
- $this->attendee = '';
6420
- $this->categories = '';
6421
- $this->class = '';
6422
- $this->comment = '';
6423
- $this->completed = '';
6424
- $this->contact = '';
6425
- $this->created = '';
6426
- $this->description = '';
6427
- $this->dtstart = '';
6428
- $this->due = '';
6429
- $this->duration = '';
6430
- $this->exdate = '';
6431
- $this->exrule = '';
6432
- $this->geo = '';
6433
- $this->lastmodified = '';
6434
- $this->location = '';
6435
- $this->organizer = '';
6436
- $this->percentcomplete = '';
6437
- $this->priority = '';
6438
- $this->rdate = '';
6439
- $this->recurrenceid = '';
6440
- $this->relatedto = '';
6441
- $this->requeststatus = '';
6442
- $this->resources = '';
6443
- $this->rrule = '';
6444
- $this->sequence = '';
6445
- $this->status = '';
6446
- $this->summary = '';
6447
- $this->url = '';
6448
- $this->xprop = '';
6449
-
6450
- $this->components = array();
6451
-
6452
- if( defined( 'ICAL_LANG' ) && !isset( $config['language'] ))
6453
- $config['language'] = ICAL_LANG;
6454
- if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE;
6455
- if( !isset( $config['nl'] )) $config['nl'] = "\r\n";
6456
- if( !isset( $config['format'] )) $config['format'] = 'iCal';
6457
- if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR;
6458
- $this->setConfig( $config );
6459
-
6460
- }
6461
- /**
6462
- * create formatted output for calendar component VTODO object instance
6463
- *
6464
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6465
- * @since 2.5.1 - 2008-11-07
6466
- * @param array $xcaldecl
6467
- * @return string
6468
- */
6469
- function createComponent( &$xcaldecl ) {
6470
- $objectname = $this->_createFormat();
6471
- $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
6472
- $component .= $this->createUid();
6473
- $component .= $this->createDtstamp();
6474
- $component .= $this->createAttach();
6475
- $component .= $this->createAttendee();
6476
- $component .= $this->createCategories();
6477
- $component .= $this->createClass();
6478
- $component .= $this->createComment();
6479
- $component .= $this->createCompleted();
6480
- $component .= $this->createContact();
6481
- $component .= $this->createCreated();
6482
- $component .= $this->createDescription();
6483
- $component .= $this->createDtstart();
6484
- $component .= $this->createDue();
6485
- $component .= $this->createDuration();
6486
- $component .= $this->createExdate();
6487
- $component .= $this->createExrule();
6488
- $component .= $this->createGeo();
6489
- $component .= $this->createLastModified();
6490
- $component .= $this->createLocation();
6491
- $component .= $this->createOrganizer();
6492
- $component .= $this->createPercentComplete();
6493
- $component .= $this->createPriority();
6494
- $component .= $this->createRdate();
6495
- $component .= $this->createRelatedTo();
6496
- $component .= $this->createRequestStatus();
6497
- $component .= $this->createRecurrenceid();
6498
- $component .= $this->createResources();
6499
- $component .= $this->createRrule();
6500
- $component .= $this->createSequence();
6501
- $component .= $this->createStatus();
6502
- $component .= $this->createSummary();
6503
- $component .= $this->createUrl();
6504
- $component .= $this->createXprop();
6505
- $component .= $this->createSubComponent();
6506
- $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
6507
- if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
6508
- foreach( $this->xcaldecl as $localxcaldecl )
6509
- $xcaldecl[] = $localxcaldecl;
6510
- }
6511
- return $component;
6512
- }
6513
- }
6514
- /*********************************************************************************/
6515
- /*********************************************************************************/
6516
- /**
6517
- * class for calendar component VJOURNAL
6518
- *
6519
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6520
- * @since 2.5.1 - 2008-10-12
6521
- */
6522
- class vjournal extends calendarComponent {
6523
- var $attach;
6524
- var $attendee;
6525
- var $categories;
6526
- var $comment;
6527
- var $contact;
6528
- var $class;
6529
- var $created;
6530
- var $description;
6531
- var $dtstart;
6532
- var $exdate;
6533
- var $exrule;
6534
- var $lastmodified;
6535
- var $organizer;
6536
- var $rdate;
6537
- var $recurrenceid;
6538
- var $relatedto;
6539
- var $requeststatus;
6540
- var $rrule;
6541
- var $sequence;
6542
- var $status;
6543
- var $summary;
6544
- var $url;
6545
- var $xprop;
6546
- /**
6547
- * constructor for calendar component VJOURNAL object
6548
- *
6549
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6550
- * @since 2.8.2 - 2011-05-01
6551
- * @param array $config
6552
- * @return void
6553
- */
6554
- function vjournal( $config = array()) {
6555
- $this->calendarComponent();
6556
-
6557
- $this->attach = '';
6558
- $this->attendee = '';
6559
- $this->categories = '';
6560
- $this->class = '';
6561
- $this->comment = '';
6562
- $this->contact = '';
6563
- $this->created = '';
6564
- $this->description = '';
6565
- $this->dtstart = '';
6566
- $this->exdate = '';
6567
- $this->exrule = '';
6568
- $this->lastmodified = '';
6569
- $this->organizer = '';
6570
- $this->rdate = '';
6571
- $this->recurrenceid = '';
6572
- $this->relatedto = '';
6573
- $this->requeststatus = '';
6574
- $this->rrule = '';
6575
- $this->sequence = '';
6576
- $this->status = '';
6577
- $this->summary = '';
6578
- $this->url = '';
6579
- $this->xprop = '';
6580
-
6581
- if( defined( 'ICAL_LANG' ) && !isset( $config['language'] ))
6582
- $config['language'] = ICAL_LANG;
6583
- if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE;
6584
- if( !isset( $config['nl'] )) $config['nl'] = "\r\n";
6585
- if( !isset( $config['format'] )) $config['format'] = 'iCal';
6586
- if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR;
6587
- $this->setConfig( $config );
6588
-
6589
- }
6590
- /**
6591
- * create formatted output for calendar component VJOURNAL object instance
6592
- *
6593
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6594
- * @since 2.5.1 - 2008-10-12
6595
- * @param array $xcaldecl
6596
- * @return string
6597
- */
6598
- function createComponent( &$xcaldecl ) {
6599
- $objectname = $this->_createFormat();
6600
- $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
6601
- $component .= $this->createUid();
6602
- $component .= $this->createDtstamp();
6603
- $component .= $this->createAttach();
6604
- $component .= $this->createAttendee();
6605
- $component .= $this->createCategories();
6606
- $component .= $this->createClass();
6607
- $component .= $this->createComment();
6608
- $component .= $this->createContact();
6609
- $component .= $this->createCreated();
6610
- $component .= $this->createDescription();
6611
- $component .= $this->createDtstart();
6612
- $component .= $this->createExdate();
6613
- $component .= $this->createExrule();
6614
- $component .= $this->createLastModified();
6615
- $component .= $this->createOrganizer();
6616
- $component .= $this->createRdate();
6617
- $component .= $this->createRequestStatus();
6618
- $component .= $this->createRecurrenceid();
6619
- $component .= $this->createRelatedTo();
6620
- $component .= $this->createRrule();
6621
- $component .= $this->createSequence();
6622
- $component .= $this->createStatus();
6623
- $component .= $this->createSummary();
6624
- $component .= $this->createUrl();
6625
- $component .= $this->createXprop();
6626
- $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
6627
- if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
6628
- foreach( $this->xcaldecl as $localxcaldecl )
6629
- $xcaldecl[] = $localxcaldecl;
6630
- }
6631
- return $component;
6632
- }
6633
- }
6634
- /*********************************************************************************/
6635
- /*********************************************************************************/
6636
- /**
6637
- * class for calendar component VFREEBUSY
6638
- *
6639
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6640
- * @since 2.5.1 - 2008-10-12
6641
- */
6642
- class vfreebusy extends calendarComponent {
6643
- var $attendee;
6644
- var $comment;
6645
- var $contact;
6646
- var $dtend;
6647
- var $dtstart;
6648
- var $duration;
6649
- var $freebusy;
6650
- var $organizer;
6651
- var $requeststatus;
6652
- var $url;
6653
- var $xprop;
6654
- // component subcomponents container
6655
- var $components;
6656
- /**
6657
- * constructor for calendar component VFREEBUSY object
6658
- *
6659
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6660
- * @since 2.8.2 - 2011-05-01
6661
- * @param array $config
6662
- * @return void
6663
- */
6664
- function vfreebusy( $config = array()) {
6665
- $this->calendarComponent();
6666
-
6667
- $this->attendee = '';
6668
- $this->comment = '';
6669
- $this->contact = '';
6670
- $this->dtend = '';
6671
- $this->dtstart = '';
6672
- $this->duration = '';
6673
- $this->freebusy = '';
6674
- $this->organizer = '';
6675
- $this->requeststatus = '';
6676
- $this->url = '';
6677
- $this->xprop = '';
6678
-
6679
- if( defined( 'ICAL_LANG' ) && !isset( $config['language'] ))
6680
- $config['language'] = ICAL_LANG;
6681
- if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE;
6682
- if( !isset( $config['nl'] )) $config['nl'] = "\r\n";
6683
- if( !isset( $config['format'] )) $config['format'] = 'iCal';
6684
- if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR;
6685
- $this->setConfig( $config );
6686
-
6687
- }
6688
- /**
6689
- * create formatted output for calendar component VFREEBUSY object instance
6690
- *
6691
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6692
- * @since 2.3.1 - 2007-11-19
6693
- * @param array $xcaldecl
6694
- * @return string
6695
- */
6696
- function createComponent( &$xcaldecl ) {
6697
- $objectname = $this->_createFormat();
6698
- $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
6699
- $component .= $this->createUid();
6700
- $component .= $this->createDtstamp();
6701
- $component .= $this->createAttendee();
6702
- $component .= $this->createComment();
6703
- $component .= $this->createContact();
6704
- $component .= $this->createDtstart();
6705
- $component .= $this->createDtend();
6706
- $component .= $this->createDuration();
6707
- $component .= $this->createFreebusy();
6708
- $component .= $this->createOrganizer();
6709
- $component .= $this->createRequestStatus();
6710
- $component .= $this->createUrl();
6711
- $component .= $this->createXprop();
6712
- $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
6713
- if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
6714
- foreach( $this->xcaldecl as $localxcaldecl )
6715
- $xcaldecl[] = $localxcaldecl;
6716
- }
6717
- return $component;
6718
- }
6719
- }
6720
- /*********************************************************************************/
6721
- /*********************************************************************************/
6722
- /**
6723
- * class for calendar component VALARM
6724
- *
6725
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6726
- * @since 2.5.1 - 2008-10-12
6727
- */
6728
- class valarm extends calendarComponent {
6729
- var $action;
6730
- var $attach;
6731
- var $attendee;
6732
- var $description;
6733
- var $duration;
6734
- var $repeat;
6735
- var $summary;
6736
- var $trigger;
6737
- var $xprop;
6738
- /**
6739
- * constructor for calendar component VALARM object
6740
- *
6741
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6742
- * @since 2.8.2 - 2011-05-01
6743
- * @param array $config
6744
- * @return void
6745
- */
6746
- function valarm( $config = array()) {
6747
- $this->calendarComponent();
6748
-
6749
- $this->action = '';
6750
- $this->attach = '';
6751
- $this->attendee = '';
6752
- $this->description = '';
6753
- $this->duration = '';
6754
- $this->repeat = '';
6755
- $this->summary = '';
6756
- $this->trigger = '';
6757
- $this->xprop = '';
6758
-
6759
- if( defined( 'ICAL_LANG' ) && !isset( $config['language'] ))
6760
- $config['language'] = ICAL_LANG;
6761
- if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE;
6762
- if( !isset( $config['nl'] )) $config['nl'] = "\r\n";
6763
- if( !isset( $config['format'] )) $config['format'] = 'iCal';
6764
- if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR;
6765
- $this->setConfig( $config );
6766
-
6767
- }
6768
- /**
6769
- * create formatted output for calendar component VALARM object instance
6770
- *
6771
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6772
- * @since 2.5.1 - 2008-10-22
6773
- * @param array $xcaldecl
6774
- * @return string
6775
- */
6776
- function createComponent( &$xcaldecl ) {
6777
- $objectname = $this->_createFormat();
6778
- $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
6779
- $component .= $this->createAction();
6780
- $component .= $this->createAttach();
6781
- $component .= $this->createAttendee();
6782
- $component .= $this->createDescription();
6783
- $component .= $this->createDuration();
6784
- $component .= $this->createRepeat();
6785
- $component .= $this->createSummary();
6786
- $component .= $this->createTrigger();
6787
- $component .= $this->createXprop();
6788
- $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
6789
- return $component;
6790
- }
6791
- }
6792
- /**********************************************************************************
6793
- /*********************************************************************************/
6794
- /**
6795
- * class for calendar component VTIMEZONE
6796
- *
6797
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6798
- * @since 2.5.1 - 2008-10-12
6799
- */
6800
- class vtimezone extends calendarComponent {
6801
- var $timezonetype;
6802
-
6803
- var $comment;
6804
- var $dtstart;
6805
- var $lastmodified;
6806
- var $rdate;
6807
- var $rrule;
6808
- var $tzid;
6809
- var $tzname;
6810
- var $tzoffsetfrom;
6811
- var $tzoffsetto;
6812
- var $tzurl;
6813
- var $xprop;
6814
- // component subcomponents container
6815
- var $components;
6816
- /**
6817
- * constructor for calendar component VTIMEZONE object
6818
- *
6819
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6820
- * @since 2.8.2 - 2011-05-01
6821
- * @param mixed $timezonetype optional, default FALSE ( STANDARD / DAYLIGHT )
6822
- * @param array $config
6823
- * @return void
6824
- */
6825
- function vtimezone( $timezonetype=FALSE, $config = array()) {
6826
- if( is_array( $timezonetype )) {
6827
- $config = $timezonetype;
6828
- $timezonetype = FALSE;
6829
- }
6830
- if( !$timezonetype )
6831
- $this->timezonetype = 'VTIMEZONE';
6832
- else
6833
- $this->timezonetype = strtoupper( $timezonetype );
6834
- $this->calendarComponent();
6835
-
6836
- $this->comment = '';
6837
- $this->dtstart = '';
6838
- $this->lastmodified = '';
6839
- $this->rdate = '';
6840
- $this->rrule = '';
6841
- $this->tzid = '';
6842
- $this->tzname = '';
6843
- $this->tzoffsetfrom = '';
6844
- $this->tzoffsetto = '';
6845
- $this->tzurl = '';
6846
- $this->xprop = '';
6847
-
6848
- $this->components = array();
6849
-
6850
- if( defined( 'ICAL_LANG' ) && !isset( $config['language'] ))
6851
- $config['language'] = ICAL_LANG;
6852
- if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE;
6853
- if( !isset( $config['nl'] )) $config['nl'] = "\r\n";
6854
- if( !isset( $config['format'] )) $config['format'] = 'iCal';
6855
- if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR;
6856
- $this->setConfig( $config );
6857
-
6858
- }
6859
- /**
6860
- * create formatted output for calendar component VTIMEZONE object instance
6861
- *
6862
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6863
- * @since 2.5.1 - 2008-10-25
6864
- * @param array $xcaldecl
6865
- * @return string
6866
- */
6867
- function createComponent( &$xcaldecl ) {
6868
- $objectname = $this->_createFormat();
6869
- $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
6870
- $component .= $this->createTzid();
6871
- $component .= $this->createLastModified();
6872
- $component .= $this->createTzurl();
6873
- $component .= $this->createDtstart();
6874
- $component .= $this->createTzoffsetfrom();
6875
- $component .= $this->createTzoffsetto();
6876
- $component .= $this->createComment();
6877
- $component .= $this->createRdate();
6878
- $component .= $this->createRrule();
6879
- $component .= $this->createTzname();
6880
- $component .= $this->createXprop();
6881
- $component .= $this->createSubComponent();
6882
- $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
6883
- if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
6884
- foreach( $this->xcaldecl as $localxcaldecl )
6885
- $xcaldecl[] = $localxcaldecl;
6886
- }
6887
- return $component;
6888
- }
6889
- }
6890
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/iCalcreator-2.14/lgpl.txt DELETED
@@ -1,504 +0,0 @@
1
- GNU LESSER GENERAL PUBLIC LICENSE
2
- Version 2.1, February 1999
3
-
4
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
5
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
- Everyone is permitted to copy and distribute verbatim copies
7
- of this license document, but changing it is not allowed.
8
-
9
- [This is the first released version of the Lesser GPL. It also counts
10
- as the successor of the GNU Library Public License, version 2, hence
11
- the version number 2.1.]
12
-
13
- Preamble
14
-
15
- The licenses for most software are designed to take away your
16
- freedom to share and change it. By contrast, the GNU General Public
17
- Licenses are intended to guarantee your freedom to share and change
18
- free software--to make sure the software is free for all its users.
19
-
20
- This license, the Lesser General Public License, applies to some
21
- specially designated software packages--typically libraries--of the
22
- Free Software Foundation and other authors who decide to use it. You
23
- can use it too, but we suggest you first think carefully about whether
24
- this license or the ordinary General Public License is the better
25
- strategy to use in any particular case, based on the explanations below.
26
-
27
- When we speak of free software, we are referring to freedom of use,
28
- not price. Our General Public Licenses are designed to make sure that
29
- you have the freedom to distribute copies of free software (and charge
30
- for this service if you wish); that you receive source code or can get
31
- it if you want it; that you can change the software and use pieces of
32
- it in new free programs; and that you are informed that you can do
33
- these things.
34
-
35
- To protect your rights, we need to make restrictions that forbid
36
- distributors to deny you these rights or to ask you to surrender these
37
- rights. These restrictions translate to certain responsibilities for
38
- you if you distribute copies of the library or if you modify it.
39
-
40
- For example, if you distribute copies of the library, whether gratis
41
- or for a fee, you must give the recipients all the rights that we gave
42
- you. You must make sure that they, too, receive or can get the source
43
- code. If you link other code with the library, you must provide
44
- complete object files to the recipients, so that they can relink them
45
- with the library after making changes to the library and recompiling
46
- it. And you must show them these terms so they know their rights.
47
-
48
- We protect your rights with a two-step method: (1) we copyright the
49
- library, and (2) we offer you this license, which gives you legal
50
- permission to copy, distribute and/or modify the library.
51
-
52
- To protect each distributor, we want to make it very clear that
53
- there is no warranty for the free library. Also, if the library is
54
- modified by someone else and passed on, the recipients should know
55
- that what they have is not the original version, so that the original
56
- author's reputation will not be affected by problems that might be
57
- introduced by others.
58
-
59
- Finally, software patents pose a constant threat to the existence of
60
- any free program. We wish to make sure that a company cannot
61
- effectively restrict the users of a free program by obtaining a
62
- restrictive license from a patent holder. Therefore, we insist that
63
- any patent license obtained for a version of the library must be
64
- consistent with the full freedom of use specified in this license.
65
-
66
- Most GNU software, including some libraries, is covered by the
67
- ordinary GNU General Public License. This license, the GNU Lesser
68
- General Public License, applies to certain designated libraries, and
69
- is quite different from the ordinary General Public License. We use
70
- this license for certain libraries in order to permit linking those
71
- libraries into non-free programs.
72
-
73
- When a program is linked with a library, whether statically or using
74
- a shared library, the combination of the two is legally speaking a
75
- combined work, a derivative of the original library. The ordinary
76
- General Public License therefore permits such linking only if the
77
- entire combination fits its criteria of freedom. The Lesser General
78
- Public License permits more lax criteria for linking other code with
79
- the library.
80
-
81
- We call this license the "Lesser" General Public License because it
82
- does Less to protect the user's freedom than the ordinary General
83
- Public License. It also provides other free software developers Less
84
- of an advantage over competing non-free programs. These disadvantages
85
- are the reason we use the ordinary General Public License for many
86
- libraries. However, the Lesser license provides advantages in certain
87
- special circumstances.
88
-
89
- For example, on rare occasions, there may be a special need to
90
- encourage the widest possible use of a certain library, so that it becomes
91
- a de-facto standard. To achieve this, non-free programs must be
92
- allowed to use the library. A more frequent case is that a free
93
- library does the same job as widely used non-free libraries. In this
94
- case, there is little to gain by limiting the free library to free
95
- software only, so we use the Lesser General Public License.
96
-
97
- In other cases, permission to use a particular library in non-free
98
- programs enables a greater number of people to use a large body of
99
- free software. For example, permission to use the GNU C Library in
100
- non-free programs enables many more people to use the whole GNU
101
- operating system, as well as its variant, the GNU/Linux operating
102
- system.
103
-
104
- Although the Lesser General Public License is Less protective of the
105
- users' freedom, it does ensure that the user of a program that is
106
- linked with the Library has the freedom and the wherewithal to run
107
- that program using a modified version of the Library.
108
-
109
- The precise terms and conditions for copying, distribution and
110
- modification follow. Pay close attention to the difference between a
111
- "work based on the library" and a "work that uses the library". The
112
- former contains code derived from the library, whereas the latter must
113
- be combined with the library in order to run.
114
-
115
- GNU LESSER GENERAL PUBLIC LICENSE
116
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
117
-
118
- 0. This License Agreement applies to any software library or other
119
- program which contains a notice placed by the copyright holder or
120
- other authorized party saying it may be distributed under the terms of
121
- this Lesser General Public License (also called "this License").
122
- Each licensee is addressed as "you".
123
-
124
- A "library" means a collection of software functions and/or data
125
- prepared so as to be conveniently linked with application programs
126
- (which use some of those functions and data) to form executables.
127
-
128
- The "Library", below, refers to any such software library or work
129
- which has been distributed under these terms. A "work based on the
130
- Library" means either the Library or any derivative work under
131
- copyright law: that is to say, a work containing the Library or a
132
- portion of it, either verbatim or with modifications and/or translated
133
- straightforwardly into another language. (Hereinafter, translation is
134
- included without limitation in the term "modification".)
135
-
136
- "Source code" for a work means the preferred form of the work for
137
- making modifications to it. For a library, complete source code means
138
- all the source code for all modules it contains, plus any associated
139
- interface definition files, plus the scripts used to control compilation
140
- and installation of the library.
141
-
142
- Activities other than copying, distribution and modification are not
143
- covered by this License; they are outside its scope. The act of
144
- running a program using the Library is not restricted, and output from
145
- such a program is covered only if its contents constitute a work based
146
- on the Library (independent of the use of the Library in a tool for
147
- writing it). Whether that is true depends on what the Library does
148
- and what the program that uses the Library does.
149
-
150
- 1. You may copy and distribute verbatim copies of the Library's
151
- complete source code as you receive it, in any medium, provided that
152
- you conspicuously and appropriately publish on each copy an
153
- appropriate copyright notice and disclaimer of warranty; keep intact
154
- all the notices that refer to this License and to the absence of any
155
- warranty; and distribute a copy of this License along with the
156
- Library.
157
-
158
- You may charge a fee for the physical act of transferring a copy,
159
- and you may at your option offer warranty protection in exchange for a
160
- fee.
161
-
162
- 2. You may modify your copy or copies of the Library or any portion
163
- of it, thus forming a work based on the Library, and copy and
164
- distribute such modifications or work under the terms of Section 1
165
- above, provided that you also meet all of these conditions:
166
-
167
- a) The modified work must itself be a software library.
168
-
169
- b) You must cause the files modified to carry prominent notices
170
- stating that you changed the files and the date of any change.
171
-
172
- c) You must cause the whole of the work to be licensed at no
173
- charge to all third parties under the terms of this License.
174
-
175
- d) If a facility in the modified Library refers to a function or a
176
- table of data to be supplied by an application program that uses
177
- the facility, other than as an argument passed when the facility
178
- is invoked, then you must make a good faith effort to ensure that,
179
- in the event an application does not supply such function or
180
- table, the facility still operates, and performs whatever part of
181
- its purpose remains meaningful.
182
-
183
- (For example, a function in a library to compute square roots has
184
- a purpose that is entirely well-defined independent of the
185
- application. Therefore, Subsection 2d requires that any
186
- application-supplied function or table used by this function must
187
- be optional: if the application does not supply it, the square
188
- root function must still compute square roots.)
189
-
190
- These requirements apply to the modified work as a whole. If
191
- identifiable sections of that work are not derived from the Library,
192
- and can be reasonably considered independent and separate works in
193
- themselves, then this License, and its terms, do not apply to those
194
- sections when you distribute them as separate works. But when you
195
- distribute the same sections as part of a whole which is a work based
196
- on the Library, the distribution of the whole must be on the terms of
197
- this License, whose permissions for other licensees extend to the
198
- entire whole, and thus to each and every part regardless of who wrote
199
- it.
200
-
201
- Thus, it is not the intent of this section to claim rights or contest
202
- your rights to work written entirely by you; rather, the intent is to
203
- exercise the right to control the distribution of derivative or
204
- collective works based on the Library.
205
-
206
- In addition, mere aggregation of another work not based on the Library
207
- with the Library (or with a work based on the Library) on a volume of
208
- a storage or distribution medium does not bring the other work under
209
- the scope of this License.
210
-
211
- 3. You may opt to apply the terms of the ordinary GNU General Public
212
- License instead of this License to a given copy of the Library. To do
213
- this, you must alter all the notices that refer to this License, so
214
- that they refer to the ordinary GNU General Public License, version 2,
215
- instead of to this License. (If a newer version than version 2 of the
216
- ordinary GNU General Public License has appeared, then you can specify
217
- that version instead if you wish.) Do not make any other change in
218
- these notices.
219
-
220
- Once this change is made in a given copy, it is irreversible for
221
- that copy, so the ordinary GNU General Public License applies to all
222
- subsequent copies and derivative works made from that copy.
223
-
224
- This option is useful when you wish to copy part of the code of
225
- the Library into a program that is not a library.
226
-
227
- 4. You may copy and distribute the Library (or a portion or
228
- derivative of it, under Section 2) in object code or executable form
229
- under the terms of Sections 1 and 2 above provided that you accompany
230
- it with the complete corresponding machine-readable source code, which
231
- must be distributed under the terms of Sections 1 and 2 above on a
232
- medium customarily used for software interchange.
233
-
234
- If distribution of object code is made by offering access to copy
235
- from a designated place, then offering equivalent access to copy the
236
- source code from the same place satisfies the requirement to
237
- distribute the source code, even though third parties are not
238
- compelled to copy the source along with the object code.
239
-
240
- 5. A program that contains no derivative of any portion of the
241
- Library, but is designed to work with the Library by being compiled or
242
- linked with it, is called a "work that uses the Library". Such a
243
- work, in isolation, is not a derivative work of the Library, and
244
- therefore falls outside the scope of this License.
245
-
246
- However, linking a "work that uses the Library" with the Library
247
- creates an executable that is a derivative of the Library (because it
248
- contains portions of the Library), rather than a "work that uses the
249
- library". The executable is therefore covered by this License.
250
- Section 6 states terms for distribution of such executables.
251
-
252
- When a "work that uses the Library" uses material from a header file
253
- that is part of the Library, the object code for the work may be a
254
- derivative work of the Library even though the source code is not.
255
- Whether this is true is especially significant if the work can be
256
- linked without the Library, or if the work is itself a library. The
257
- threshold for this to be true is not precisely defined by law.
258
-
259
- If such an object file uses only numerical parameters, data
260
- structure layouts and accessors, and small macros and small inline
261
- functions (ten lines or less in length), then the use of the object
262
- file is unrestricted, regardless of whether it is legally a derivative
263
- work. (Executables containing this object code plus portions of the
264
- Library will still fall under Section 6.)
265
-
266
- Otherwise, if the work is a derivative of the Library, you may
267
- distribute the object code for the work under the terms of Section 6.
268
- Any executables containing that work also fall under Section 6,
269
- whether or not they are linked directly with the Library itself.
270
-
271
- 6. As an exception to the Sections above, you may also combine or
272
- link a "work that uses the Library" with the Library to produce a
273
- work containing portions of the Library, and distribute that work
274
- under terms of your choice, provided that the terms permit
275
- modification of the work for the customer's own use and reverse
276
- engineering for debugging such modifications.
277
-
278
- You must give prominent notice with each copy of the work that the
279
- Library is used in it and that the Library and its use are covered by
280
- this License. You must supply a copy of this License. If the work
281
- during execution displays copyright notices, you must include the
282
- copyright notice for the Library among them, as well as a reference
283
- directing the user to the copy of this License. Also, you must do one
284
- of these things:
285
-
286
- a) Accompany the work with the complete corresponding
287
- machine-readable source code for the Library including whatever
288
- changes were used in the work (which must be distributed under
289
- Sections 1 and 2 above); and, if the work is an executable linked
290
- with the Library, with the complete machine-readable "work that
291
- uses the Library", as object code and/or source code, so that the
292
- user can modify the Library and then relink to produce a modified
293
- executable containing the modified Library. (It is understood
294
- that the user who changes the contents of definitions files in the
295
- Library will not necessarily be able to recompile the application
296
- to use the modified definitions.)
297
-
298
- b) Use a suitable shared library mechanism for linking with the
299
- Library. A suitable mechanism is one that (1) uses at run time a
300
- copy of the library already present on the user's computer system,
301
- rather than copying library functions into the executable, and (2)
302
- will operate properly with a modified version of the library, if
303
- the user installs one, as long as the modified version is
304
- interface-compatible with the version that the work was made with.
305
-
306
- c) Accompany the work with a written offer, valid for at
307
- least three years, to give the same user the materials
308
- specified in Subsection 6a, above, for a charge no more
309
- than the cost of performing this distribution.
310
-
311
- d) If distribution of the work is made by offering access to copy
312
- from a designated place, offer equivalent access to copy the above
313
- specified materials from the same place.
314
-
315
- e) Verify that the user has already received a copy of these
316
- materials or that you have already sent this user a copy.
317
-
318
- For an executable, the required form of the "work that uses the
319
- Library" must include any data and utility programs needed for
320
- reproducing the executable from it. However, as a special exception,
321
- the materials to be distributed need not include anything that is
322
- normally distributed (in either source or binary form) with the major
323
- components (compiler, kernel, and so on) of the operating system on
324
- which the executable runs, unless that component itself accompanies
325
- the executable.
326
-
327
- It may happen that this requirement contradicts the license
328
- restrictions of other proprietary libraries that do not normally
329
- accompany the operating system. Such a contradiction means you cannot
330
- use both them and the Library together in an executable that you
331
- distribute.
332
-
333
- 7. You may place library facilities that are a work based on the
334
- Library side-by-side in a single library together with other library
335
- facilities not covered by this License, and distribute such a combined
336
- library, provided that the separate distribution of the work based on
337
- the Library and of the other library facilities is otherwise
338
- permitted, and provided that you do these two things:
339
-
340
- a) Accompany the combined library with a copy of the same work
341
- based on the Library, uncombined with any other library
342
- facilities. This must be distributed under the terms of the
343
- Sections above.
344
-
345
- b) Give prominent notice with the combined library of the fact
346
- that part of it is a work based on the Library, and explaining
347
- where to find the accompanying uncombined form of the same work.
348
-
349
- 8. You may not copy, modify, sublicense, link with, or distribute
350
- the Library except as expressly provided under this License. Any
351
- attempt otherwise to copy, modify, sublicense, link with, or
352
- distribute the Library is void, and will automatically terminate your
353
- rights under this License. However, parties who have received copies,
354
- or rights, from you under this License will not have their licenses
355
- terminated so long as such parties remain in full compliance.
356
-
357
- 9. You are not required to accept this License, since you have not
358
- signed it. However, nothing else grants you permission to modify or
359
- distribute the Library or its derivative works. These actions are
360
- prohibited by law if you do not accept this License. Therefore, by
361
- modifying or distributing the Library (or any work based on the
362
- Library), you indicate your acceptance of this License to do so, and
363
- all its terms and conditions for copying, distributing or modifying
364
- the Library or works based on it.
365
-
366
- 10. Each time you redistribute the Library (or any work based on the
367
- Library), the recipient automatically receives a license from the
368
- original licensor to copy, distribute, link with or modify the Library
369
- subject to these terms and conditions. You may not impose any further
370
- restrictions on the recipients' exercise of the rights granted herein.
371
- You are not responsible for enforcing compliance by third parties with
372
- this License.
373
-
374
- 11. If, as a consequence of a court judgment or allegation of patent
375
- infringement or for any other reason (not limited to patent issues),
376
- conditions are imposed on you (whether by court order, agreement or
377
- otherwise) that contradict the conditions of this License, they do not
378
- excuse you from the conditions of this License. If you cannot
379
- distribute so as to satisfy simultaneously your obligations under this
380
- License and any other pertinent obligations, then as a consequence you
381
- may not distribute the Library at all. For example, if a patent
382
- license would not permit royalty-free redistribution of the Library by
383
- all those who receive copies directly or indirectly through you, then
384
- the only way you could satisfy both it and this License would be to
385
- refrain entirely from distribution of the Library.
386
-
387
- If any portion of this section is held invalid or unenforceable under any
388
- particular circumstance, the balance of the section is intended to apply,
389
- and the section as a whole is intended to apply in other circumstances.
390
-
391
- It is not the purpose of this section to induce you to infringe any
392
- patents or other property right claims or to contest validity of any
393
- such claims; this section has the sole purpose of protecting the
394
- integrity of the free software distribution system which is
395
- implemented by public license practices. Many people have made
396
- generous contributions to the wide range of software distributed
397
- through that system in reliance on consistent application of that
398
- system; it is up to the author/donor to decide if he or she is willing
399
- to distribute software through any other system and a licensee cannot
400
- impose that choice.
401
-
402
- This section is intended to make thoroughly clear what is believed to
403
- be a consequence of the rest of this License.
404
-
405
- 12. If the distribution and/or use of the Library is restricted in
406
- certain countries either by patents or by copyrighted interfaces, the
407
- original copyright holder who places the Library under this License may add
408
- an explicit geographical distribution limitation excluding those countries,
409
- so that distribution is permitted only in or among countries not thus
410
- excluded. In such case, this License incorporates the limitation as if
411
- written in the body of this License.
412
-
413
- 13. The Free Software Foundation may publish revised and/or new
414
- versions of the Lesser General Public License from time to time.
415
- Such new versions will be similar in spirit to the present version,
416
- but may differ in detail to address new problems or concerns.
417
-
418
- Each version is given a distinguishing version number. If the Library
419
- specifies a version number of this License which applies to it and
420
- "any later version", you have the option of following the terms and
421
- conditions either of that version or of any later version published by
422
- the Free Software Foundation. If the Library does not specify a
423
- license version number, you may choose any version ever published by
424
- the Free Software Foundation.
425
-
426
- 14. If you wish to incorporate parts of the Library into other free
427
- programs whose distribution conditions are incompatible with these,
428
- write to the author to ask for permission. For software which is
429
- copyrighted by the Free Software Foundation, write to the Free
430
- Software Foundation; we sometimes make exceptions for this. Our
431
- decision will be guided by the two goals of preserving the free status
432
- of all derivatives of our free software and of promoting the sharing
433
- and reuse of software generally.
434
-
435
- NO WARRANTY
436
-
437
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
438
- WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
439
- EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
440
- OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
441
- KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
442
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
443
- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
444
- LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
445
- THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
446
-
447
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
448
- WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
449
- AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
450
- FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
451
- CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
452
- LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
453
- RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
454
- FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
455
- SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
456
- DAMAGES.
457
-
458
- END OF TERMS AND CONDITIONS
459
-
460
- How to Apply These Terms to Your New Libraries
461
-
462
- If you develop a new library, and you want it to be of the greatest
463
- possible use to the public, we recommend making it free software that
464
- everyone can redistribute and change. You can do so by permitting
465
- redistribution under these terms (or, alternatively, under the terms of the
466
- ordinary General Public License).
467
-
468
- To apply these terms, attach the following notices to the library. It is
469
- safest to attach them to the start of each source file to most effectively
470
- convey the exclusion of warranty; and each file should have at least the
471
- "copyright" line and a pointer to where the full notice is found.
472
-
473
- <one line to give the library's name and a brief idea of what it does.>
474
- Copyright (C) <year> <name of author>
475
-
476
- This library is free software; you can redistribute it and/or
477
- modify it under the terms of the GNU Lesser General Public
478
- License as published by the Free Software Foundation; either
479
- version 2.1 of the License, or (at your option) any later version.
480
-
481
- This library is distributed in the hope that it will be useful,
482
- but WITHOUT ANY WARRANTY; without even the implied warranty of
483
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
484
- Lesser General Public License for more details.
485
-
486
- You should have received a copy of the GNU Lesser General Public
487
- License along with this library; if not, write to the Free Software
488
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
489
-
490
- Also add information on how to contact you by electronic and paper mail.
491
-
492
- You should also get your employer (if you work as a programmer) or your
493
- school, if any, to sign a "copyright disclaimer" for the library, if
494
- necessary. Here is a sample; alter the names:
495
-
496
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
497
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.
498
-
499
- <signature of Ty Coon>, 1 April 1990
500
- Ty Coon, President of Vice
501
-
502
- That's all there is to it!
503
-
504
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/{iCalcreator-2.14 → iCalcreator-2.16}/iCalcreator.class.php RENAMED
@@ -1,13 +1,13 @@
1
  <?php
2
  /*********************************************************************************/
3
  /**
4
- * iCalcreator v2.14
5
  * copyright (c) 2007-2012 Kjell-Inge Gustafsson kigkonsult
6
  * kigkonsult.se/iCalcreator/index.php
7
  * ical@kigkonsult.se
8
  *
9
  * Description:
10
- * This file is a PHP implementation of RFC 2445/5545.
11
  *
12
  * This library is free software; you can redistribute it and/or
13
  * modify it under the terms of the GNU Lesser General Public
@@ -45,7 +45,7 @@ if ($pos !== false) {
45
  */
46
  /*********************************************************************************/
47
  /* version, do NOT remove!! */
48
- define( 'ICALCREATOR_VERSION', 'iCalcreator 2.14' );
49
  /*********************************************************************************/
50
  /*********************************************************************************/
51
  /**
@@ -1423,9 +1423,10 @@ class vcalendar {
1423
  */
1424
  function selectComponents2( $selectOptions ) {
1425
  $output = array();
 
1426
  $allowedProperties = array( 'ATTENDEE', 'CATEGORIES', 'CONTACT', 'LOCATION', 'ORGANIZER', 'PRIORITY', 'RELATED-TO', 'RESOURCES', 'STATUS', 'SUMMARY', 'UID', 'URL' );
1427
  foreach( $this->components as $cix => $component3 ) {
1428
- if( !in_array( $component3->objName, array('vevent', 'vtodo', 'vjournal', 'vfreebusy' )))
1429
  continue;
1430
  $uid = $component3->getProperty( 'UID' );
1431
  foreach( $selectOptions as $propName => $pvalue ) {
@@ -1539,7 +1540,7 @@ class vcalendar {
1539
  * sort iCal compoments
1540
  *
1541
  * ascending sort on properties (if exist) x-current-dtstart, dtstart,
1542
- * x-current-dtend, dtend, x-current-due, due, duration, created, dtstamp, uid if called without arguments,
1543
  * otherwise sorting on specific (argument) property values
1544
  *
1545
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
@@ -1581,18 +1582,18 @@ class vcalendar {
1581
  continue;
1582
  }
1583
  if( FALSE !== ( $d = $c->getProperty( 'X-CURRENT-DTSTART' ))) {
1584
- $c->srtk[0] = iCalUtilityFunctions::_date_time_string( $d[1] );
1585
  unset( $c->srtk[0]['unparsedtext'] );
1586
  }
1587
  elseif( FALSE === ( $c->srtk[0] = $c->getProperty( 'dtstart' )))
1588
  $c->srtk[1] = 0; // sortkey 0 : dtstart
1589
  if( FALSE !== ( $d = $c->getProperty( 'X-CURRENT-DTEND' ))) {
1590
- $c->srtk[1] = iCalUtilityFunctions::_date_time_string( $d[1] ); // sortkey 1 : dtend/due(/dtstart+duration)
1591
  unset( $c->srtk[1]['unparsedtext'] );
1592
  }
1593
  elseif( FALSE === ( $c->srtk[1] = $c->getProperty( 'dtend' ))) {
1594
  if( FALSE !== ( $d = $c->getProperty( 'X-CURRENT-DUE' ))) {
1595
- $c->srtk[1] = iCalUtilityFunctions::_date_time_string( $d[1] );
1596
  unset( $c->srtk[1]['unparsedtext'] );
1597
  }
1598
  elseif( FALSE === ( $c->srtk[1] = $c->getProperty( 'due' )))
@@ -1649,7 +1650,7 @@ class vcalendar {
1649
  * parse iCal text/file into vcalendar, components, properties and parameters
1650
  *
1651
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1652
- * @since 2.12.17 - 2012-07-12
1653
  * @param mixed $unparsedtext, optional, strict rfc2445 formatted, single property string or array of property strings
1654
  * @return bool FALSE if error occurs during parsing
1655
  *
@@ -1745,35 +1746,22 @@ class vcalendar {
1745
  /* parse data for calendar (this) object */
1746
  if( isset( $this->unparsed ) && is_array( $this->unparsed ) && ( 0 < count( $this->unparsed ))) {
1747
  /* concatenate property values spread over several lines */
1748
- $lastix = -1;
1749
  $propnames = array( 'calscale','method','prodid','version','x-' );
1750
  $proprows = array();
1751
- foreach( $this->unparsed as $line ) {
1752
- $newProp = FALSE;
1753
- foreach ( $propnames as $propname ) {
1754
- if( $propname == strtolower( substr( $line, 0, strlen( $propname )))) {
1755
- $newProp = TRUE;
1756
- break;
1757
- }
1758
- }
1759
- if( $newProp ) {
1760
- $newProp = FALSE;
1761
- $lastix++;
1762
- $proprows[$lastix] = $line;
1763
- }
1764
- else
1765
- $proprows[$lastix] .= '!"#¤%&/()=?'.$line;
1766
  }
1767
  $paramMStz = array( 'utc-', 'utc+', 'gmt-', 'gmt+' );
1768
  $paramProto3 = array( 'fax:', 'cid:', 'sms:', 'tel:', 'urn:' );
1769
  $paramProto4 = array( 'crid:', 'news:', 'pres:' );
1770
  foreach( $proprows as $line ) {
1771
- $line = str_replace( '!"#¤%&/()=? ', '', $line );
1772
- $line = str_replace( '!"#¤%&/()=?', '', $line );
1773
  if( '\n' == substr( $line, -2 ))
1774
  $line = substr( $line, 0, -2 );
1775
  /* get property name */
1776
- $propname = null;
1777
  $cix = 0;
1778
  while( FALSE !== ( $char = substr( $line, $cix, 1 ))) {
1779
  if( in_array( $char, array( ':', ';' )))
@@ -1782,9 +1770,13 @@ class vcalendar {
1782
  $propname .= $char;
1783
  $cix++;
1784
  }
 
 
 
1785
  /* ignore version/prodid properties */
1786
- if( in_array( strtoupper( $propname ), array( 'VERSION', 'PRODID' )))
1787
  continue;
 
1788
  $line = substr( $line, $cix);
1789
  /* separate attributes from value */
1790
  $attr = array();
@@ -2514,7 +2506,7 @@ class calendarComponent {
2514
  if( $this->getConfig( 'allowEmpty' ))
2515
  return $this->_createElement( 'COMPLETED' );
2516
  else return FALSE;
2517
- $formatted = iCalUtilityFunctions::_format_date_time( $this->completed['value'], 7 );
2518
  $attributes = $this->_createParams( $this->completed['params'] );
2519
  return $this->_createElement( 'COMPLETED', $attributes, $formatted );
2520
  }
@@ -2596,7 +2588,7 @@ class calendarComponent {
2596
  */
2597
  function createCreated() {
2598
  if( empty( $this->created )) return FALSE;
2599
- $formatted = iCalUtilityFunctions::_format_date_time( $this->created['value'], 7 );
2600
  $attributes = $this->_createParams( $this->created['params'] );
2601
  return $this->_createElement( 'CREATED', $attributes, $formatted );
2602
  }
@@ -2670,7 +2662,7 @@ class calendarComponent {
2670
  * creates formatted output for calendar component property dtend
2671
  *
2672
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2673
- * @since 2.9.6 - 2011-05-14
2674
  * @return string
2675
  */
2676
  function createDtend() {
@@ -2684,11 +2676,8 @@ class calendarComponent {
2684
  if( $this->getConfig( 'allowEmpty' ))
2685
  return $this->_createElement( 'DTEND' );
2686
  else return FALSE;
2687
- $formatted = iCalUtilityFunctions::_format_date_time( $this->dtend['value'] );
2688
- if(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
2689
- ( !isset( $this->dtend['params']['VALUE'] ) || ( $this->dtend['params']['VALUE'] != 'DATE' )) &&
2690
- !isset( $this->dtend['params']['TZID'] ))
2691
- $this->dtend['params']['TZID'] = $tzid;
2692
  $attributes = $this->_createParams( $this->dtend['params'] );
2693
  return $this->_createElement( 'DTEND', $attributes, $formatted );
2694
  }
@@ -2738,7 +2727,7 @@ class calendarComponent {
2738
  !isset( $this->dtstamp['value']['min'] ) &&
2739
  !isset( $this->dtstamp['value']['sec'] ))
2740
  $this->_makeDtstamp();
2741
- $formatted = iCalUtilityFunctions::_format_date_time( $this->dtstamp['value'], 7 );
2742
  $attributes = $this->_createParams( $this->dtstamp['params'] );
2743
  return $this->_createElement( 'DTSTAMP', $attributes, $formatted );
2744
  }
@@ -2746,17 +2735,13 @@ class calendarComponent {
2746
  * computes datestamp for calendar component object instance dtstamp
2747
  *
2748
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2749
- * @since 2.10.9 - 2011-08-10
2750
  * @return void
2751
  */
2752
  function _makeDtstamp() {
2753
- $d = mktime( date('H'), date('i'), (date('s') - date( 'Z' )), date('m'), date('d'), date('Y'));
2754
- $this->dtstamp['value'] = array( 'year' => date( 'Y', $d )
2755
- , 'month' => date( 'm', $d )
2756
- , 'day' => date( 'd', $d )
2757
- , 'hour' => date( 'H', $d )
2758
- , 'min' => date( 'i', $d )
2759
- , 'sec' => date( 's', $d ));
2760
  $this->dtstamp['params'] = null;
2761
  }
2762
  /**
@@ -2788,7 +2773,7 @@ class calendarComponent {
2788
  * creates formatted output for calendar component property dtstart
2789
  *
2790
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2791
- * @since 2.9.6 - 2011-05-15
2792
  * @return string
2793
  */
2794
  function createDtstart() {
@@ -2805,11 +2790,8 @@ class calendarComponent {
2805
  }
2806
  if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' )))
2807
  unset( $this->dtstart['value']['tz'], $this->dtstart['params']['TZID'] );
2808
- elseif(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
2809
- ( !isset( $this->dtstart['params']['VALUE'] ) || ( $this->dtstart['params']['VALUE'] != 'DATE' )) &&
2810
- !isset( $this->dtstart['params']['TZID'] ))
2811
- $this->dtstart['params']['TZID'] = $tzid;
2812
- $formatted = iCalUtilityFunctions::_format_date_time( $this->dtstart['value'] );
2813
  $attributes = $this->_createParams( $this->dtstart['params'] );
2814
  return $this->_createElement( 'DTSTART', $attributes, $formatted );
2815
  }
@@ -2848,7 +2830,7 @@ class calendarComponent {
2848
  * creates formatted output for calendar component property due
2849
  *
2850
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2851
- * @since 2.4.8 - 2008-10-22
2852
  * @return string
2853
  */
2854
  function createDue() {
@@ -2864,11 +2846,8 @@ class calendarComponent {
2864
  else
2865
  return FALSE;
2866
  }
2867
- $formatted = iCalUtilityFunctions::_format_date_time( $this->due['value'] );
2868
- if(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
2869
- ( !isset( $this->due['params']['VALUE'] ) || ( $this->due['params']['VALUE'] != 'DATE' )) &&
2870
- !isset( $this->due['params']['TZID'] ))
2871
- $this->due['params']['TZID'] = $tzid;
2872
  $attributes = $this->_createParams( $this->due['params'] );
2873
  return $this->_createElement( 'DUE', $attributes, $formatted );
2874
  }
@@ -2920,7 +2899,7 @@ class calendarComponent {
2920
  return $this->_createElement( 'DURATION', array(), null );
2921
  else return FALSE;
2922
  $attributes = $this->_createParams( $this->duration['params'] );
2923
- return $this->_createElement( 'DURATION', $attributes, iCalUtilityFunctions::_format_duration( $this->duration['value'] ));
2924
  }
2925
  /**
2926
  * set calendar component property duration
@@ -2938,17 +2917,17 @@ class calendarComponent {
2938
  function setDuration( $week, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
2939
  if( empty( $week )) if( $this->getConfig( 'allowEmpty' )) $week = null; else return FALSE;
2940
  if( is_array( $week ) && ( 1 <= count( $week )))
2941
- $this->duration = array( 'value' => iCalUtilityFunctions::_duration_array( $week ), 'params' => iCalUtilityFunctions::_setParams( $day ));
2942
  elseif( is_string( $week ) && ( 3 <= strlen( trim( $week )))) {
2943
  $week = trim( $week );
2944
  if( in_array( substr( $week, 0, 1 ), array( '+', '-' )))
2945
  $week = substr( $week, 1 );
2946
- $this->duration = array( 'value' => iCalUtilityFunctions::_duration_string( $week ), 'params' => iCalUtilityFunctions::_setParams( $day ));
2947
  }
2948
  elseif( empty( $week ) && empty( $day ) && empty( $hour ) && empty( $min ) && empty( $sec ))
2949
  return FALSE;
2950
  else
2951
- $this->duration = array( 'value' => iCalUtilityFunctions::_duration_array( array( $week, $day, $hour, $min, $sec )), 'params' => iCalUtilityFunctions::_setParams( $params ));
2952
  return TRUE;
2953
  }
2954
  /*********************************************************************************/
@@ -2973,7 +2952,7 @@ class calendarComponent {
2973
  $content = $attributes = null;
2974
  foreach( $theExdate['value'] as $eix => $exdatePart ) {
2975
  $parno = count( $exdatePart );
2976
- $formatted = iCalUtilityFunctions::_format_date_time( $exdatePart, $parno );
2977
  if( isset( $theExdate['params']['TZID'] ))
2978
  $formatted = str_replace( 'Z', '', $formatted);
2979
  if( 0 < $eix ) {
@@ -3000,7 +2979,7 @@ class calendarComponent {
3000
  * set calendar component property exdate
3001
  *
3002
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3003
- * @since 2.11.8 - 2012-01-19
3004
  * @param array exdates
3005
  * @param array $params, optional
3006
  * @param integer $index, optional
@@ -3022,12 +3001,27 @@ class calendarComponent {
3022
  iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default parameter
3023
  foreach( $exdates as $eix => $theExdate ) {
3024
  iCalUtilityFunctions::_strDate2arr( $theExdate );
3025
- if( iCalUtilityFunctions::_isArrayTimestampDate( $theExdate ))
 
 
 
 
 
 
3026
  $exdatea = iCalUtilityFunctions::_timestamp2date( $theExdate, $parno );
3027
- elseif( is_array( $theExdate ))
3028
- $exdatea = iCalUtilityFunctions::_date_time_array( $theExdate, $parno );
 
 
 
 
 
 
 
 
 
3029
  elseif( 8 <= strlen( trim( $theExdate ))) { // ex. 2006-08-03 10:12:18
3030
- $exdatea = iCalUtilityFunctions::_date_time_string( $theExdate, $parno );
3031
  unset( $exdatea['unparsedtext'] );
3032
  }
3033
  if( 3 == $parno )
@@ -3115,7 +3109,7 @@ class calendarComponent {
3115
  $fno = 1;
3116
  $cnt = count( $freebusyPart['value']);
3117
  foreach( $freebusyPart['value'] as $periodix => $freebusyPeriod ) {
3118
- $formatted = iCalUtilityFunctions::_format_date_time( $freebusyPeriod[0] );
3119
  $content .= $formatted;
3120
  $content .= '/';
3121
  $cnt2 = count( $freebusyPeriod[1]);
@@ -3127,10 +3121,10 @@ class calendarComponent {
3127
  isset( $freebusyPeriod[1]['year'] ) &&
3128
  isset( $freebusyPeriod[1]['month'] ) &&
3129
  isset( $freebusyPeriod[1]['day'] )) {
3130
- $content .= iCalUtilityFunctions::_format_date_time( $freebusyPeriod[1] );
3131
  }
3132
  else { // period= -> dur-time
3133
- $content .= iCalUtilityFunctions::_format_duration( $freebusyPeriod[1] );
3134
  }
3135
  if( $fno < $cnt )
3136
  $content .= ',';
@@ -3173,7 +3167,7 @@ class calendarComponent {
3173
  $freebusyPairMember = array();
3174
  if( is_array( $fbMember )) {
3175
  if( iCalUtilityFunctions::_isArrayDate( $fbMember )) { // date-time value
3176
- $freebusyPairMember = iCalUtilityFunctions::_date_time_array( $fbMember, 7 );
3177
  $freebusyPairMember['tz'] = 'Z';
3178
  }
3179
  elseif( iCalUtilityFunctions::_isArrayTimestampDate( $fbMember )) { // timestamp value
@@ -3181,17 +3175,17 @@ class calendarComponent {
3181
  $freebusyPairMember['tz'] = 'Z';
3182
  }
3183
  else { // array format duration
3184
- $freebusyPairMember = iCalUtilityFunctions::_duration_array( $fbMember );
3185
  }
3186
  }
3187
  elseif(( 3 <= strlen( trim( $fbMember ))) && // string format duration
3188
  ( in_array( $fbMember{0}, array( 'P', '+', '-' )))) {
3189
  if( 'P' != $fbMember{0} )
3190
  $fbmember = substr( $fbMember, 1 );
3191
- $freebusyPairMember = iCalUtilityFunctions::_duration_string( $fbMember );
3192
  }
3193
  elseif( 8 <= strlen( trim( $fbMember ))) { // text date ex. 2006-08-03 10:12:18
3194
- $freebusyPairMember = iCalUtilityFunctions::_date_time_string( $fbMember, 7 );
3195
  unset( $freebusyPairMember['unparsedtext'] );
3196
  $freebusyPairMember['tz'] = 'Z';
3197
  }
@@ -3270,7 +3264,7 @@ class calendarComponent {
3270
  function createLastModified() {
3271
  if( empty( $this->lastmodified )) return FALSE;
3272
  $attributes = $this->_createParams( $this->lastmodified['params'] );
3273
- $formatted = iCalUtilityFunctions::_format_date_time( $this->lastmodified['value'], 7 );
3274
  return $this->_createElement( 'LAST-MODIFIED', $attributes, $formatted );
3275
  }
3276
  /**
@@ -3444,7 +3438,7 @@ class calendarComponent {
3444
  * creates formatted output for calendar component property rdate
3445
  *
3446
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3447
- * @since 2.4.16 - 2008-10-26
3448
  * @return string
3449
  */
3450
  function createRdate() {
@@ -3453,7 +3447,7 @@ class calendarComponent {
3453
  $output = null;
3454
  if( $utctime )
3455
  unset( $this->rdate['params']['TZID'] );
3456
- foreach( $this->rdate as $theRdate ) {
3457
  if( empty( $theRdate['value'] )) {
3458
  if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RDATE' );
3459
  continue;
@@ -3464,22 +3458,15 @@ class calendarComponent {
3464
  $cnt = count( $theRdate['value'] );
3465
  $content = null;
3466
  $rno = 1;
3467
- foreach( $theRdate['value'] as $rpix => $rdatePart ) {
3468
  $contentPart = null;
3469
  if( is_array( $rdatePart ) &&
3470
  isset( $theRdate['params']['VALUE'] ) && ( 'PERIOD' == $theRdate['params']['VALUE'] )) { // PERIOD
3471
  if( $utctime )
3472
  unset( $rdatePart[0]['tz'] );
3473
- $formatted = iCalUtilityFunctions::_format_date_time( $rdatePart[0]); // PERIOD part 1
3474
  if( $utctime || !empty( $theRdate['params']['TZID'] ))
3475
  $formatted = str_replace( 'Z', '', $formatted);
3476
- if( 0 < $rpix ) {
3477
- if( !empty( $rdatePart[0]['tz'] ) && iCalUtilityFunctions::_isOffset( $rdatePart[0]['tz'] )) {
3478
- if( 'Z' != substr( $formatted, -1 )) $formatted .= 'Z';
3479
- }
3480
- else
3481
- $formatted = str_replace( 'Z', '', $formatted );
3482
- }
3483
  $contentPart .= $formatted;
3484
  $contentPart .= '/';
3485
  $cnt2 = count( $rdatePart[1]);
@@ -3497,34 +3484,22 @@ class calendarComponent {
3497
  isset( $rdatePart[1]['day'] )) {
3498
  if( $utctime )
3499
  unset( $rdatePart[1]['tz'] );
3500
- $formatted = iCalUtilityFunctions::_format_date_time( $rdatePart[1] ); // PERIOD part 2
3501
  if( $utctime || !empty( $theRdate['params']['TZID'] ))
3502
- $formatted = str_replace( 'Z', '', $formatted);
3503
- if( !empty( $rdatePart[0]['tz'] ) && iCalUtilityFunctions::_isOffset( $rdatePart[0]['tz'] )) {
3504
- if( 'Z' != substr( $formatted, -1 )) $formatted .= 'Z';
3505
- }
3506
- else
3507
  $formatted = str_replace( 'Z', '', $formatted );
3508
  $contentPart .= $formatted;
3509
  }
3510
  else { // period= -> dur-time
3511
- $contentPart .= iCalUtilityFunctions::_format_duration( $rdatePart[1] );
3512
  }
3513
  } // PERIOD end
3514
  else { // SINGLE date start
3515
  if( $utctime )
3516
  unset( $rdatePart['tz'] );
3517
- $formatted = iCalUtilityFunctions::_format_date_time( $rdatePart);
 
3518
  if( $utctime || !empty( $theRdate['params']['TZID'] ))
3519
  $formatted = str_replace( 'Z', '', $formatted);
3520
- if( !$utctime && ( 0 < $rpix )) {
3521
- if( !empty( $theRdate['value'][0]['tz'] ) && iCalUtilityFunctions::_isOffset( $theRdate['value'][0]['tz'] )) {
3522
- if( 'Z' != substr( $formatted, -1 ))
3523
- $formatted .= 'Z';
3524
- }
3525
- else
3526
- $formatted = str_replace( 'Z', '', $formatted );
3527
- }
3528
  $contentPart .= $formatted;
3529
  }
3530
  $content .= $contentPart;
@@ -3540,7 +3515,7 @@ class calendarComponent {
3540
  * set calendar component property rdate
3541
  *
3542
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3543
- * @since 2.11.8 - 2012-01-31
3544
  * @param array $rdates
3545
  * @param array $params, optional
3546
  * @param integer $index, optional
@@ -3585,68 +3560,97 @@ class calendarComponent {
3585
  foreach( $theRdate as $rix => $rPeriod ) {
3586
  iCalUtilityFunctions::_strDate2arr( $theRdate );
3587
  if( is_array( $rPeriod )) {
3588
- if( iCalUtilityFunctions::_isArrayTimestampDate( $rPeriod )) // timestamp
3589
- $inputab = ( isset( $rPeriod['tz'] )) ? iCalUtilityFunctions::_timestamp2date( $rPeriod, $parno ) : iCalUtilityFunctions::_timestamp2date( $rPeriod, 6 );
3590
- elseif( iCalUtilityFunctions::_isArrayDate( $rPeriod ))
3591
- $inputab = ( 3 < count ( $rPeriod )) ? iCalUtilityFunctions::_date_time_array( $rPeriod, $parno ) : iCalUtilityFunctions::_date_time_array( $rPeriod, 6 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3592
  elseif (( 1 == count( $rPeriod )) && ( 8 <= strlen( reset( $rPeriod )))) { // text-date
3593
- $inputab = iCalUtilityFunctions::_date_time_string( reset( $rPeriod ), $parno );
3594
  unset( $inputab['unparsedtext'] );
3595
  }
3596
  else // array format duration
3597
- $inputab = iCalUtilityFunctions::_duration_array( $rPeriod );
3598
  }
3599
  elseif(( 3 <= strlen( trim( $rPeriod ))) && // string format duration
3600
  ( in_array( $rPeriod[0], array( 'P', '+', '-' )))) {
3601
  if( 'P' != $rPeriod[0] )
3602
- $rPeriod = substr( $rPeriod, 1 );
3603
- $inputab = iCalUtilityFunctions::_duration_string( $rPeriod );
3604
  }
3605
  elseif( 8 <= strlen( trim( $rPeriod ))) { // text date ex. 2006-08-03 10:12:18
3606
- $inputab = iCalUtilityFunctions::_date_time_string( $rPeriod, $parno );
3607
  unset( $inputab['unparsedtext'] );
3608
  }
3609
- if( isset( $input['params']['TZID'] ) ||
3610
- ( isset( $inputab['tz'] ) && !iCalUtilityFunctions::_isOffset( $inputab['tz'] )) ||
3611
- ( isset( $inputa[0] ) && ( !isset( $inputa[0]['tz'] ))) ||
3612
- ( isset( $inputa[0]['tz'] ) && !iCalUtilityFunctions::_isOffset( $inputa[0]['tz'] )))
3613
- unset( $inputab['tz'] );
3614
- if( $toZ )
3615
- $inputab['tz'] = 'Z';
3616
- $inputa[] = $inputab;
 
 
 
 
 
 
 
3617
  }
3618
  } // PERIOD end
3619
  elseif ( iCalUtilityFunctions::_isArrayTimestampDate( $theRdate )) { // timestamp
 
 
 
 
 
 
3620
  $inputa = iCalUtilityFunctions::_timestamp2date( $theRdate, $parno );
3621
- if( $toZ )
3622
- $inputa['tz'] = 'Z';
3623
  }
3624
  else { // date[-time]
3625
- $inputa = iCalUtilityFunctions::_date_time_array( $theRdate, $parno );
3626
- $toZ = ( isset( $inputa['tz'] ) && in_array( strtoupper( $inputa['tz'] ), $zArr )) ? TRUE : FALSE;
3627
- if( $toZ )
3628
- $inputa['tz'] = 'Z';
 
 
3629
  }
3630
  }
3631
  elseif( 8 <= strlen( trim( $theRdate ))) { // text date ex. 2006-08-03 10:12:18
3632
- $inputa = iCalUtilityFunctions::_date_time_string( $theRdate, $parno );
3633
  unset( $inputa['unparsedtext'] );
3634
  if( $toZ )
3635
- $inputa['tz'] = 'Z';
3636
  }
3637
  if( !isset( $input['params']['VALUE'] ) || ( 'PERIOD' != $input['params']['VALUE'] )) { // no PERIOD
 
 
 
 
3638
  if( 3 == $parno )
3639
  unset( $inputa['hour'], $inputa['min'], $inputa['sec'], $inputa['tz'] );
3640
  elseif( isset( $inputa['tz'] ))
3641
- $inputa['tz'] = (string) $inputa['tz'];
3642
- if( isset( $input['params']['TZID'] ) ||
3643
- ( isset( $inputa['tz'] ) && !iCalUtilityFunctions::_isOffset( $inputa['tz'] )) ||
3644
- ( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] ))) ||
3645
- ( isset( $input['value'][0]['tz'] ) && !iCalUtilityFunctions::_isOffset( $input['value'][0]['tz'] )))
3646
  if( !$toZ )
3647
  unset( $inputa['tz'] );
3648
  }
3649
- $input['value'][] = $inputa;
3650
  }
3651
  if( 3 == $parno ) {
3652
  $input['params']['VALUE'] = 'DATE';
@@ -3665,18 +3669,15 @@ class calendarComponent {
3665
  * creates formatted output for calendar component property recurrence-id
3666
  *
3667
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3668
- * @since 2.9.6 - 2011-05-15
3669
  * @return string
3670
  */
3671
  function createRecurrenceid() {
3672
  if( empty( $this->recurrenceid )) return FALSE;
3673
  if( empty( $this->recurrenceid['value'] ))
3674
  return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'RECURRENCE-ID' ) : FALSE;
3675
- $formatted = iCalUtilityFunctions::_format_date_time( $this->recurrenceid['value'] );
3676
- if(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
3677
- ( !isset( $this->recurrenceid['params']['VALUE'] ) || ( $this->recurrenceid['params']['VALUE'] != 'DATE' )) &&
3678
- !isset( $this->recurrenceid['params']['TZID'] ))
3679
- $this->recurrenceid['params']['TZID'] = $tzid;
3680
  $attributes = $this->_createParams( $this->recurrenceid['params'] );
3681
  return $this->_createElement( 'RECURRENCE-ID', $attributes, $formatted );
3682
  }
@@ -4047,13 +4048,13 @@ class calendarComponent {
4047
  if( isset( $this->trigger['value']['year'] ) &&
4048
  isset( $this->trigger['value']['month'] ) &&
4049
  isset( $this->trigger['value']['day'] ))
4050
- $content .= iCalUtilityFunctions::_format_date_time( $this->trigger['value'] );
4051
  else {
4052
  if( TRUE !== $this->trigger['value']['relatedStart'] )
4053
  $attributes .= $this->intAttrDelimiter.'RELATED=END';
4054
  if( $this->trigger['value']['before'] )
4055
  $content .= '-';
4056
- $content .= iCalUtilityFunctions::_format_duration( $this->trigger['value'] );
4057
  }
4058
  $attributes .= $this->_createParams( $this->trigger['params'] );
4059
  return $this->_createElement( 'TRIGGER', $attributes, $content );
@@ -4062,7 +4063,7 @@ class calendarComponent {
4062
  * set calendar component property trigger
4063
  *
4064
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4065
- * @since 2.10.30 - 2012-01-16
4066
  * @param mixed $year
4067
  * @param mixed $month optional
4068
  * @param int $day optional
@@ -4083,7 +4084,7 @@ class calendarComponent {
4083
  }
4084
  else
4085
  return FALSE;
4086
- if( iCalUtilityFunctions::_isArrayTimestampDate( $year )) { // timestamp
4087
  $params = iCalUtilityFunctions::_setParams( $month );
4088
  $date = iCalUtilityFunctions::_timestamp2date( $year, 7 );
4089
  foreach( $date as $k => $v )
@@ -4116,10 +4117,10 @@ class calendarComponent {
4116
  $before = ( '-' == $year[0] ) ? TRUE : FALSE;
4117
  if( 'P' != $year[0] )
4118
  $year = substr( $year, 1 );
4119
- $date = iCalUtilityFunctions::_duration_string( $year);
4120
  }
4121
  else // date
4122
- $date = iCalUtilityFunctions::_date_time_string( $year, 7 );
4123
  unset( $year, $month, $day, $date['unparsedtext'] );
4124
  if( empty( $date ))
4125
  $sec = 0;
@@ -4723,7 +4724,7 @@ class calendarComponent {
4723
  * creates formatted output for calendar component property data value type recur
4724
  *
4725
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4726
- * @since 2.4.8 - 2008-10-22
4727
  * @param array $recurlabel
4728
  * @param array $recurdata
4729
  * @return string
@@ -4744,8 +4745,8 @@ class calendarComponent {
4744
  break;
4745
  }
4746
  case 'UNTIL': {
4747
- $content2 .= ";UNTIL=";
4748
- $content2 .= iCalUtilityFunctions::_format_date_time( $rulevalue );
4749
  break;
4750
  }
4751
  case 'COUNT':
@@ -4886,10 +4887,11 @@ class calendarComponent {
4886
  case 'PROPINFO':
4887
  $output = array();
4888
  if( !in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) {
4889
- if( empty( $this->uid['value'] )) $this->_makeuid();
4890
  $output['UID'] = 1;
 
 
4891
  }
4892
- if( !empty( $this->dtstamp )) $output['DTSTAMP'] = 1;
4893
  if( !empty( $this->summary )) $output['SUMMARY'] = 1;
4894
  if( !empty( $this->description )) $output['DESCRIPTION'] = count( $this->description );
4895
  if( !empty( $this->dtstart )) $output['DTSTART'] = 1;
@@ -4935,6 +4937,9 @@ class calendarComponent {
4935
  if( !empty( $this->xprop )) $output['X-PROP'] = count( $this->xprop );
4936
  return $output;
4937
  break;
 
 
 
4938
  case 'TZID':
4939
  return $this->dtzid;
4940
  break;
@@ -5771,14 +5776,14 @@ class calendarComponent {
5771
  * parse component unparsed data into properties
5772
  *
5773
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
5774
- * @since 2.12.17 - 2012-07-15
5775
  * @param mixed $unparsedtext, optional, strict rfc2445 formatted, single property string or array of strings
5776
  * @return bool FALSE if error occurs during parsing
5777
  *
5778
  */
5779
  function parse( $unparsedtext=null ) {
 
5780
  if( !empty( $unparsedtext )) {
5781
- $nl = $this->getConfig( 'nl' );
5782
  if( is_array( $unparsedtext ))
5783
  $unparsedtext = implode( '\n'.$nl, $unparsedtext );
5784
  $unparsedtext = explode( $nl, iCalUtilityFunctions::convEolChar( $unparsedtext, $nl ));
@@ -5853,32 +5858,20 @@ class calendarComponent {
5853
  , 'summary', 'transp', 'trigger', 'tzid', 'tzname', 'tzoffsetfrom'
5854
  , 'tzoffsetto', 'tzurl', 'uid', 'url', 'x-' );
5855
  $proprows = array();
5856
- foreach( $this->unparsed as $line ) {
5857
- $newProp = FALSE;
5858
- foreach ( $propnames as $propname ) {
5859
- if( $propname == strtolower( substr( $line, 0, strlen( $propname )))) {
5860
- $newProp = TRUE;
5861
- break;
5862
- }
5863
- }
5864
- if( $newProp ) {
5865
- $newProp = FALSE;
5866
- $lastix++;
5867
- $proprows[$lastix] = $line;
5868
- }
5869
- else
5870
- $proprows[$lastix] .= '!"#¤%&/()=?'.$line;
5871
  }
5872
  /* parse each property 'line' */
5873
  $paramMStz = array( 'utc-', 'utc+', 'gmt-', 'gmt+' );
5874
  $paramProto3 = array( 'fax:', 'cid:', 'sms:', 'tel:', 'urn:' );
5875
  $paramProto4 = array( 'crid:', 'news:', 'pres:' );
5876
  foreach( $proprows as $line ) {
5877
- $line = str_replace( '!"#¤%&/()=? ', '', $line );
5878
- $line = str_replace( '!"#¤%&/()=?', '', $line );
5879
  if( '\n' == substr( $line, -2 ))
5880
  $line = substr( $line, 0, -2 );
5881
- /* get propname, (problem with x-properties, otherwise in previous loop) */
5882
  $propname = null;
5883
  $cix = 0;
5884
  while( isset( $line[$cix] )) {
@@ -5892,6 +5885,8 @@ class calendarComponent {
5892
  $propname2 = $propname;
5893
  $propname = 'X-';
5894
  }
 
 
5895
  /* rest of the line is opt.params and value */
5896
  $line = substr( $line, $cix );
5897
  /* separate attributes from value */
@@ -6123,13 +6118,11 @@ class calendarComponent {
6123
  * return a copy of this component
6124
  *
6125
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6126
- * @since 2.8.8 - 2011-03-15
6127
  * @return object
6128
  */
6129
  function copy() {
6130
- $serialized_contents = serialize( $this );
6131
- $copy = unserialize( $serialized_contents );
6132
- return $copy;
6133
  }
6134
  /*********************************************************************************/
6135
  /*********************************************************************************/
@@ -7224,13 +7217,56 @@ class iCalUtilityFunctions {
7224
  return self::$m_pInstance;
7225
  }
7226
  /**
7227
- * check a date(-time) for an opt. timezone and if it is a DATE-TIME or DATE
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7228
  *
7229
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7230
  * @since 2.10.30 - 2012-01-16
7231
  * @param array $date, date to check
7232
  * @param int $parno, no of date parts (i.e. year, month.. .)
7233
- * @return array $params, property parameters
 
7234
  */
7235
  public static function _chkdatecfg( $theDate, & $parno, & $params ) {
7236
  if( isset( $params['TZID'] ))
@@ -7263,7 +7299,7 @@ class iCalUtilityFunctions {
7263
  elseif((( 8 == strlen( $date ) && ctype_digit( $date )) || ( 11 >= strlen( $date ))) &&
7264
  ( !isset( $params['VALUE'] ) || !in_array( $params['VALUE'], array( 'DATE-TIME', 'PERIOD' ))))
7265
  $parno = 3; // DATE
7266
- $date = iCalUtilityFunctions::_date_time_string( $date, $parno );
7267
  unset( $date['unparsedtext'] );
7268
  if( !empty( $date['tz'] )) {
7269
  $parno = 7;
@@ -7280,8 +7316,8 @@ class iCalUtilityFunctions {
7280
  /**
7281
  * byte oriented line folding fix
7282
  *
7283
- * remove any line-endings that include spaces or tabs
7284
- * and convert all line endings to $nl value (that defaults to \r\n)
7285
  * takes care of '\r\n', '\r' and '\n' and mixed '\r\n'+'\r', '\r\n'+'\n'
7286
  *
7287
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
@@ -7313,7 +7349,7 @@ class iCalUtilityFunctions {
7313
  return $outp;
7314
  }
7315
  /**
7316
- * create timezone and standard/daylight components
7317
  *
7318
  * Result when 'Europe/Stockholm' and no from/to arguments is used as timezone:
7319
  *
@@ -7334,113 +7370,96 @@ class iCalUtilityFunctions {
7334
  * END:VTIMEZONE
7335
  *
7336
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7337
- * @since 2.13.2 - 2012-07-28
7338
  * Generates components for all transitions in a date range, based on contribution by Yitzchok Lavi <icalcreator@onebigsystem.com>
7339
  * Additional changes jpirkey
7340
  * @param object $calendar, reference to an iCalcreator calendar instance
7341
  * @param string $timezone, a PHP5 (DateTimeZone) valid timezone
7342
  * @param array $xProp, *[x-propName => x-propValue], optional
7343
- * @param int $from an unix timestamp
7344
- * @param int $to an unix timestamp
7345
  * @return bool
7346
  */
7347
  public static function createTimezone( & $calendar, $timezone, $xProp=array(), $from=null, $to=null ) {
7348
- if( substr( phpversion(), 0, 3 ) < '5.2' )
7349
- return FALSE;
7350
  if( empty( $timezone ))
7351
  return FALSE;
 
 
 
 
7352
  try {
7353
  $dtz = new DateTimeZone( $timezone );
7354
  $transitions = $dtz->getTransitions();
7355
- unset( $dtz );
7356
  $utcTz = new DateTimeZone( 'UTC' );
7357
  }
7358
- catch( Exception $e ) {
7359
- return FALSE;
7360
- }
7361
- if( empty( $to ))
7362
  $dates = array_keys( $calendar->getProperty( 'dtstart' ));
7363
- $transCnt = 2; // number of transitions in output if empty input $from/$to and an empty dates-array
7364
- $dateFrom = new DateTime( 'now' );
7365
- $dateTo = new DateTime( 'now' );
7366
  if( !empty( $from ))
7367
- $dateFrom->setTimestamp( $from );
7368
  else {
7369
- if( !empty( $dates ))
7370
- $dateFrom = new DateTime( reset( $dates )); // set lowest date to the lowest dtstart date
7371
  $dateFrom->modify( '-1 month' ); // set $dateFrom to one month before the lowest date
 
7372
  }
7373
- $dateFrom->setTimezone( $utcTz ); // convert local date to UTC
7374
  if( !empty( $to ))
7375
- $dateTo->setTimestamp( $to );
7376
  else {
7377
- if( !empty( $dates )) {
7378
- $dateTo = new DateTime( end( $dates )); // set highest date to the highest dtstart date
7379
- $to = $dateTo->getTimestamp(); // set mark that a highest date is found
7380
- }
7381
  $dateTo->modify( '+1 year' ); // set $dateTo to one year after the highest date
 
7382
  }
7383
- $dateTo->setTimezone( $utcTz ); // convert local date to UTC
 
7384
  $transTemp = array();
7385
- $prevOffsetfrom = $stdCnt = $dlghtCnt = 0;
7386
  $stdIx = $dlghtIx = null;
7387
- $date = new DateTime( 'now', $utcTz );
7388
  $prevTrans = FALSE;
7389
  foreach( $transitions as $tix => $trans ) { // all transitions in date-time order!!
7390
- $date->setTimestamp( $trans['ts'] ); // set transition date (UTC)
7391
- if ( $date < $dateFrom ) {
 
7392
  $prevOffsetfrom = $trans['offset']; // previous trans offset will be 'next' trans offsetFrom
7393
  $prevTrans = $trans; // save it in case we don't find any that match
7394
  $prevTrans['offsetfrom'] = ( 0 < $tix ) ? $transitions[$tix-1]['offset'] : 0;
7395
  continue;
7396
  }
7397
- if( $date > $dateTo )
7398
  break; // loop always (?) breaks here
7399
  if( !empty( $prevOffsetfrom ) || ( 0 == $prevOffsetfrom )) {
7400
  $trans['offsetfrom'] = $prevOffsetfrom; // i.e. set previous offsetto as offsetFrom
7401
  $date->modify( $trans['offsetfrom'].'seconds' ); // convert utc date to local date
7402
- $trans['time'] = array( 'year' => $date->format( 'Y' ) // set dtstart to array to ease up dtstart and (opt) rdate setting
7403
- , 'month' => $date->format( 'n' )
7404
- , 'day' => $date->format( 'j' )
7405
- , 'hour' => $date->format( 'G' )
7406
- , 'min' => $date->format( 'i' )
7407
- , 'sec' => $date->format( 's' ));
7408
  }
7409
  $prevOffsetfrom = $trans['offset'];
7410
- $trans['prevYear'] = $trans['time']['year'];
7411
  if( TRUE !== $trans['isdst'] ) { // standard timezone
7412
- if( !empty( $stdIx ) && isset( $transTemp[$stdIx]['offsetfrom'] ) && // check for any rdate's (in strict year order)
7413
- ( $transTemp[$stdIx]['abbr'] == $trans['abbr'] ) &&
7414
- ( $transTemp[$stdIx]['offsetfrom'] == $trans['offsetfrom'] ) &&
7415
- ( $transTemp[$stdIx]['offset'] == $trans['offset'] ) &&
7416
- (($transTemp[$stdIx]['prevYear'] + 1) == $trans['time']['year'] )) {
7417
- $transTemp[$stdIx]['prevYear'] = $trans['time']['year'];
7418
- $transTemp[$stdIx]['rdate'][] = $trans['time'];
7419
  continue;
7420
  }
7421
  $stdIx = $tix;
7422
- $stdCnt += 1;
7423
  } // end standard timezone
7424
  else { // daylight timezone
7425
- if( !empty( $dlghtIx ) && isset( $transTemp[$dlghtIx]['offsetfrom'] ) && // check for any rdate's (in strict year order)
7426
- ( $transTemp[$dlghtIx]['abbr'] == $trans['abbr'] ) &&
7427
- ( $transTemp[$dlghtIx]['offsetfrom'] == $trans['offsetfrom'] ) &&
7428
- ( $transTemp[$dlghtIx]['offset'] == $trans['offset'] ) &&
7429
- (($transTemp[$dlghtIx]['prevYear'] + 1) == $trans['time']['year'] )) {
7430
- $transTemp[$dlghtIx]['prevYear'] = $trans['time']['year'];
7431
- $transTemp[$dlghtIx]['rdate'][] = $trans['time'];
7432
  continue;
7433
  }
7434
  $dlghtIx = $tix;
7435
- $dlghtCnt += 1;
7436
  } // end daylight timezone
7437
- if( empty( $to ) && ( $transCnt == count( $transTemp ))) { // store only $transCnt transitions
7438
- if( TRUE !== $transTemp[0]['isdst'] )
7439
- $stdCnt -= 1;
7440
- else
7441
- $dlghtCnt -= 1;
7442
- array_shift( $transTemp );
7443
- } // end if( empty( $to ) && ( $transCnt == count( $transTemp )))
7444
  $transTemp[$tix] = $trans;
7445
  } // end foreach( $transitions as $tix => $trans )
7446
  $tz = & $calendar->newComponent( 'vtimezone' );
@@ -7452,30 +7471,27 @@ class iCalUtilityFunctions {
7452
  }
7453
  if( empty( $transTemp )) { // if no match found
7454
  if( $prevTrans ) { // then we use the last transition (before startdate) for the tz info
7455
- $date->setTimestamp( $prevTrans['ts'] ); // set transition date (UTC)
7456
  $date->modify( $prevTrans['offsetfrom'].'seconds' ); // convert utc date to local date
7457
- $prevTrans['time'] = array( 'year' => $date->format( 'Y' ) // set dtstart to array to ease up dtstart setting
7458
- , 'month' => $date->format( 'n' )
7459
- , 'day' => $date->format( 'j' )
7460
- , 'hour' => $date->format( 'G' )
7461
- , 'min' => $date->format( 'i' )
7462
- , 'sec' => $date->format( 's' ));
7463
  $transTemp[0] = $prevTrans;
7464
  }
7465
  else { // or we use the timezone identifier to BUILD the standard tz info (?)
7466
- $date = new DateTime( $timezone );
7467
- $transTemp[0] = array( 'time' => $date->format( 'Y-m-d\TH:i:sO' )
7468
  , 'offset' => $date->format( 'Z' )
7469
  , 'offsetfrom' => $date->format( 'Z' )
7470
- , 'isdst' => false );
7471
  }
7472
  }
7473
  unset( $transitions, $date, $prevTrans );
7474
- foreach( $transTemp as $trans ) {
7475
  $type = ( TRUE !== $trans['isdst'] ) ? 'standard' : 'daylight';
7476
  $scomp = & $tz->newComponent( $type );
7477
  $scomp->setProperty( 'dtstart', $trans['time'] );
7478
- // $scomp->setProperty( 'x-utc-timestamp', $trans['ts'] ); // test ###
7479
  if( !empty( $trans['abbr'] ))
7480
  $scomp->setProperty( 'tzname', $trans['abbr'] );
7481
  if( isset( $trans['offsetfrom'] ))
@@ -7487,213 +7503,122 @@ class iCalUtilityFunctions {
7487
  return TRUE;
7488
  }
7489
  /**
7490
- * convert a date/datetime (array) to timestamp
7491
  *
7492
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7493
- * @since 2.4.8 - 2008-10-30
7494
- * @param array $datetime datetime/(date)
7495
- * @param string $tz timezone
7496
- * @return timestamp
7497
  */
7498
- public static function _date2timestamp( $datetime, $tz=null ) {
7499
- $output = null;
7500
- if( !isset( $datetime['hour'] )) $datetime['hour'] = '0';
7501
- if( !isset( $datetime['min'] )) $datetime['min'] = '0';
7502
- if( !isset( $datetime['sec'] )) $datetime['sec'] = '0';
7503
- foreach( $datetime as $dkey => $dvalue ) {
7504
- if( 'tz' != $dkey )
7505
- $datetime[$dkey] = (integer) $dvalue;
7506
- }
7507
- if( $tz )
7508
- $datetime['tz'] = $tz;
7509
- $offset = ( isset( $datetime['tz'] ) && ( '' < trim ( $datetime['tz'] ))) ? iCalUtilityFunctions::_tz2offset( $datetime['tz'] ) : 0;
7510
- $output = mktime( $datetime['hour'], $datetime['min'], ($datetime['sec'] + $offset), $datetime['month'], $datetime['day'], $datetime['year'] );
7511
- return $output;
7512
  }
7513
- /**
7514
- * ensures internal date-time/date format for input date-time/date in array format
7515
- *
7516
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7517
- * @since 2.11.4 - 2012-03-18
7518
- * @param array $datetime
7519
- * @param int $parno optional, default FALSE
7520
- * @return array
7521
- */
7522
- public static function _date_time_array( $datetime, $parno=FALSE ) {
7523
- $output = array();
7524
- foreach( $datetime as $dateKey => $datePart ) {
7525
- switch ( $dateKey ) {
7526
- case '0': case 'year': $output['year'] = $datePart; break;
7527
- case '1': case 'month': $output['month'] = $datePart; break;
7528
- case '2': case 'day': $output['day'] = $datePart; break;
7529
- }
7530
- if( 3 != $parno ) {
7531
- switch ( $dateKey ) {
7532
- case '0':
7533
- case '1':
7534
- case '2': break;
7535
- case '3': case 'hour': $output['hour'] = $datePart; break;
7536
- case '4': case 'min' : $output['min'] = $datePart; break;
7537
- case '5': case 'sec' : $output['sec'] = $datePart; break;
7538
- case '6': case 'tz' : $output['tz'] = $datePart; break;
 
 
 
 
 
 
 
7539
  }
7540
  }
7541
- }
7542
- if( 3 != $parno ) {
7543
- if( !isset( $output['hour'] ))
7544
- $output['hour'] = 0;
7545
- if( !isset( $output['min'] ))
7546
- $output['min'] = 0;
7547
- if( !isset( $output['sec'] ))
7548
- $output['sec'] = 0;
7549
- if( isset( $output['tz'] ) && ( 'Z' != $output['tz'] ) &&
7550
- (( '+0000' == $output['tz'] ) || ( '-0000' == $output['tz'] ) || ( '+000000' == $output['tz'] ) || ( '-000000' == $output['tz'] )))
7551
- $output['tz'] = 'Z';
7552
  }
7553
  return $output;
7554
  }
7555
  /**
7556
- * ensures internal date-time/date format for input date-time/date in string fromat
7557
  *
7558
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7559
- * @since 2.10.30 - 2012-01-06
7560
- * Modified to also return original string value by Yitzchok Lavi <icalcreator@onebigsystem.com>
7561
- * @param array $datetime
7562
- * @param int $parno optional, default FALSE
7563
- * @return array
7564
  */
7565
- public static function _date_time_string( $datetime, $parno=FALSE ) {
7566
- // save original input string to return it later
7567
- $unparseddatetime = $datetime;
7568
- $datetime = (string) trim( $datetime );
7569
- $tz = null;
7570
- $len = strlen( $datetime ) - 1;
7571
- if( 'Z' == substr( $datetime, -1 )) {
7572
- $tz = 'Z';
7573
- $datetime = trim( substr( $datetime, 0, $len ));
7574
- }
7575
- elseif( ( ctype_digit( substr( $datetime, -2, 2 ))) && // time or date
7576
- ( '-' == substr( $datetime, -3, 1 )) ||
7577
- ( ':' == substr( $datetime, -3, 1 )) ||
7578
- ( '.' == substr( $datetime, -3, 1 ))) {
7579
- $continue = TRUE;
7580
- }
7581
- elseif( ( ctype_digit( substr( $datetime, -4, 4 ))) && // 4 pos offset
7582
- ( ' +' == substr( $datetime, -6, 2 )) ||
7583
- ( ' -' == substr( $datetime, -6, 2 ))) {
7584
- $tz = substr( $datetime, -5, 5 );
7585
- $datetime = substr( $datetime, 0, ($len - 5));
7586
- }
7587
- elseif( ( ctype_digit( substr( $datetime, -6, 6 ))) && // 6 pos offset
7588
- ( ' +' == substr( $datetime, -8, 2 )) ||
7589
- ( ' -' == substr( $datetime, -8, 2 ))) {
7590
- $tz = substr( $datetime, -7, 7 );
7591
- $datetime = substr( $datetime, 0, ($len - 7));
7592
- }
7593
- elseif( ( 6 < $len ) && ( ctype_digit( substr( $datetime, -6, 6 )))) {
7594
- $continue = TRUE;
7595
- }
7596
- elseif( 'T' == substr( $datetime, -7, 1 )) {
7597
- $continue = TRUE;
7598
- }
7599
- else {
7600
- $cx = $tx = 0; // 19970415T133000 US-Eastern
7601
- for( $cx = -1; $cx > ( 9 - $len ); $cx-- ) {
7602
- $char = substr( $datetime, $cx, 1 );
7603
- if(( ' ' == $char) || ctype_digit( $char))
7604
- break; // if exists, tz ends here.. . ?
7605
- else
7606
- $tx--; // tz length counter
7607
  }
7608
- if( 0 > $tx ) {
7609
- $tz = substr( $datetime, $tx );
7610
- $datetime = trim( substr( $datetime, 0, $len + $tx + 1 ));
7611
- }
7612
- }
7613
- if( 0 < substr_count( $datetime, '-' )) {
7614
- $datetime = str_replace( '-', '/', $datetime );
7615
- }
7616
- elseif( ctype_digit( substr( $datetime, 0, 8 )) &&
7617
- ( 'T' == substr( $datetime, 8, 1 )) &&
7618
- ctype_digit( substr( $datetime, 9, 6 ))) {
7619
- }
7620
- $datestring = date( 'Y-m-d H:i:s', strtotime( $datetime ));
7621
- $tz = trim( $tz );
7622
- $output = array();
7623
- $output['year'] = substr( $datestring, 0, 4 );
7624
- $output['month'] = substr( $datestring, 5, 2 );
7625
- $output['day'] = substr( $datestring, 8, 2 );
7626
- if(( 6 == $parno ) || ( 7 == $parno ) || ( !$parno && ( 'Z' == $tz ))) {
7627
- $output['hour'] = substr( $datestring, 11, 2 );
7628
- $output['min'] = substr( $datestring, 14, 2 );
7629
- $output['sec'] = substr( $datestring, 17, 2 );
7630
- if( !empty( $tz ))
7631
- $output['tz'] = $tz;
7632
  }
7633
- elseif( 3 != $parno ) {
7634
- if(( '00' < substr( $datestring, 11, 2 )) ||
7635
- ( '00' < substr( $datestring, 14, 2 )) ||
7636
- ( '00' < substr( $datestring, 17, 2 ))) {
7637
- $output['hour'] = substr( $datestring, 11, 2 );
7638
- $output['min'] = substr( $datestring, 14, 2 );
7639
- $output['sec'] = substr( $datestring, 17, 2 );
7640
- }
7641
- if( !empty( $tz ))
7642
- $output['tz'] = $tz;
 
 
7643
  }
7644
- // return original string in the array in case strtotime failed to make sense of it
7645
- $output['unparsedtext'] = $unparseddatetime;
7646
  return $output;
7647
  }
7648
- /**
7649
- * convert local startdate/enddate (Ymd[His]) to duration array
7650
- *
7651
- * uses this component dates if missing input dates
7652
- *
7653
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7654
- * @since 2.6.11 - 2010-10-21
7655
- * @param array $startdate
7656
- * @param array $duration
7657
- * @return array duration
7658
- */
7659
- public static function _date2duration( $startdate, $enddate ) {
7660
- $startWdate = mktime( 0, 0, 0, $startdate['month'], $startdate['day'], $startdate['year'] );
7661
- $endWdate = mktime( 0, 0, 0, $enddate['month'], $enddate['day'], $enddate['year'] );
7662
- $wduration = $endWdate - $startWdate;
7663
- $dur = array();
7664
- $dur['week'] = (int) floor( $wduration / ( 7 * 24 * 60 * 60 ));
7665
- $wduration = $wduration % ( 7 * 24 * 60 * 60 );
7666
- $dur['day'] = (int) floor( $wduration / ( 24 * 60 * 60 ));
7667
- $wduration = $wduration % ( 24 * 60 * 60 );
7668
- $dur['hour'] = (int) floor( $wduration / ( 60 * 60 ));
7669
- $wduration = $wduration % ( 60 * 60 );
7670
- $dur['min'] = (int) floor( $wduration / ( 60 ));
7671
- $dur['sec'] = (int) $wduration % ( 60 );
7672
- return $dur;
7673
- }
7674
  /**
7675
  * ensures internal duration format for input in array format
7676
  *
7677
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7678
- * @since 2.1.1 - 2007-06-24
7679
  * @param array $duration
7680
  * @return array
7681
  */
7682
  public static function _duration_array( $duration ) {
 
 
 
7683
  $output = array();
7684
  if( is_array( $duration ) &&
7685
  ( 1 == count( $duration )) &&
7686
  isset( $duration['sec'] ) &&
7687
  ( 60 < $duration['sec'] )) {
7688
  $durseconds = $duration['sec'];
7689
- $output['week'] = floor( $durseconds / ( 60 * 60 * 24 * 7 ));
7690
- $durseconds = $durseconds % ( 60 * 60 * 24 * 7 );
7691
- $output['day'] = floor( $durseconds / ( 60 * 60 * 24 ));
7692
- $durseconds = $durseconds % ( 60 * 60 * 24 );
7693
- $output['hour'] = floor( $durseconds / ( 60 * 60 ));
7694
- $durseconds = $durseconds % ( 60 * 60 );
7695
- $output['min'] = floor( $durseconds / ( 60 ));
7696
- $output['sec'] = ( $durseconds % ( 60 ));
7697
  }
7698
  else {
7699
  foreach( $duration as $durKey => $durValue ) {
@@ -7724,14 +7649,46 @@ class iCalUtilityFunctions {
7724
  return $output;
7725
  }
7726
  /**
7727
- * ensures internal duration format for input in string format
7728
  *
7729
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7730
- * @since 2.0.5 - 2007-03-14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7731
  * @param string $duration
7732
  * @return array
7733
  */
7734
  public static function _duration_string( $duration ) {
 
 
 
7735
  $duration = (string) trim( $duration );
7736
  while( 'P' != strtoupper( substr( $duration, 0, 1 ))) {
7737
  if( 0 < strlen( $duration ))
@@ -7773,51 +7730,47 @@ class iCalUtilityFunctions {
7773
  $val .= substr( $duration, $ix, 1 );
7774
  }
7775
  }
7776
- return iCalUtilityFunctions::_duration_array( $output );
7777
  }
7778
  /**
7779
- * convert duration to date in array format
7780
  *
7781
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7782
- * @since 2.8.7 - 2011-03-03
7783
- * @param array $startdate
7784
- * @param array $duration
7785
- * @return array, date format
7786
  */
7787
- public static function _duration2date( $startdate=null, $duration=null ) {
7788
- if( empty( $startdate )) return FALSE;
7789
- if( empty( $duration )) return FALSE;
7790
- $dateOnly = ( isset( $startdate['hour'] ) || isset( $startdate['min'] ) || isset( $startdate['sec'] )) ? FALSE : TRUE;
7791
- $startdate['hour'] = ( isset( $startdate['hour'] )) ? $startdate['hour'] : 0;
7792
- $startdate['min'] = ( isset( $startdate['min'] )) ? $startdate['min'] : 0;
7793
- $startdate['sec'] = ( isset( $startdate['sec'] )) ? $startdate['sec'] : 0;
7794
- $dtend = 0;
7795
- if( isset( $duration['week'] ))
7796
- $dtend += ( $duration['week'] * 7 * 24 * 60 * 60 );
7797
- if( isset( $duration['day'] ))
7798
- $dtend += ( $duration['day'] * 24 * 60 * 60 );
7799
- if( isset( $duration['hour'] ))
7800
- $dtend += ( $duration['hour'] * 60 *60 );
7801
- if( isset( $duration['min'] ))
7802
- $dtend += ( $duration['min'] * 60 );
7803
- if( isset( $duration['sec'] ))
7804
- $dtend += $duration['sec'];
7805
- $dtend = mktime( $startdate['hour'], $startdate['min'], ( $startdate['sec'] + $dtend ), $startdate['month'], $startdate['day'], $startdate['year'] );
7806
- $dtend2 = array();
7807
- $dtend2['year'] = date('Y', $dtend );
7808
- $dtend2['month'] = date('m', $dtend );
7809
- $dtend2['day'] = date('d', $dtend );
7810
- $dtend2['hour'] = date('H', $dtend );
7811
- $dtend2['min'] = date('i', $dtend );
7812
- $dtend2['sec'] = date('s', $dtend );
7813
- if( isset( $startdate['tz'] ))
7814
- $dtend2['tz'] = $startdate['tz'];
7815
- if( $dateOnly && (( 0 == $dtend2['hour'] ) && ( 0 == $dtend2['min'] ) && ( 0 == $dtend2['sec'] )))
7816
- unset( $dtend2['hour'], $dtend2['min'], $dtend2['sec'] );
7817
- return $dtend2;
7818
  }
7819
  /**
7820
- * if not preSet, if exist, remove key with expected value from array and return hit value else return elseValue
7821
  *
7822
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7823
  * @since 2.4.16 - 2008-11-08
@@ -7845,91 +7798,7 @@ class iCalUtilityFunctions {
7845
  return $elseVal;
7846
  }
7847
  /**
7848
- * creates formatted output for calendar component property data value type date/date-time
7849
- *
7850
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7851
- * @since 2.11.8 - 2012-03-17
7852
- * @param array $datetime
7853
- * @param int $parno, optional, default 6
7854
- * @return string
7855
- */
7856
- public static function _format_date_time( $datetime, $parno=6 ) {
7857
- if( !isset( $datetime['year'] ) &&
7858
- !isset( $datetime['month'] ) &&
7859
- !isset( $datetime['day'] ) &&
7860
- !isset( $datetime['hour'] ) &&
7861
- !isset( $datetime['min'] ) &&
7862
- !isset( $datetime['sec'] ))
7863
- return ;
7864
- $output = null;
7865
- foreach( $datetime as $dkey => & $dvalue )
7866
- if( 'tz' != $dkey ) $dvalue = (integer) $dvalue;
7867
- $output = sprintf( '%04d%02d%02d', $datetime['year'], $datetime['month'], $datetime['day'] );
7868
- if( isset( $datetime['hour'] ) ||
7869
- isset( $datetime['min'] ) ||
7870
- isset( $datetime['sec'] ) ||
7871
- isset( $datetime['tz'] )) {
7872
- if( isset( $datetime['tz'] ) &&
7873
- !isset( $datetime['hour'] ))
7874
- $datetime['hour'] = 0;
7875
- if( isset( $datetime['hour'] ) &&
7876
- !isset( $datetime['min'] ))
7877
- $datetime['min'] = 0;
7878
- if( isset( $datetime['hour'] ) &&
7879
- isset( $datetime['min'] ) &&
7880
- !isset( $datetime['sec'] ))
7881
- $datetime['sec'] = 0;
7882
- $output .= sprintf( 'T%02d%02d%02d', $datetime['hour'], $datetime['min'], $datetime['sec'] );
7883
- if( isset( $datetime['tz'] ) && ( '' < trim( $datetime['tz'] ))) {
7884
- $datetime['tz'] = trim( $datetime['tz'] );
7885
- if( 'Z' == $datetime['tz'] )
7886
- $output .= 'Z';
7887
- $offset = iCalUtilityFunctions::_tz2offset( $datetime['tz'] );
7888
- if( 0 != $offset ) {
7889
- $date = mktime( $datetime['hour'], $datetime['min'], ($datetime['sec'] - $offset), $datetime['month'], $datetime['day'], $datetime['year']);
7890
- $output = date( 'Ymd\THis\Z', $date );
7891
- }
7892
- }
7893
- elseif( 7 == $parno )
7894
- $output .= 'Z';
7895
- }
7896
- return $output;
7897
- }
7898
- /**
7899
- * creates formatted output for calendar component property data value type duration
7900
- *
7901
- * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7902
- * @since 2.9.9 - 2011-06-17
7903
- * @param array $duration ( week, day, hour, min, sec )
7904
- * @return string
7905
- */
7906
- public static function _format_duration( $duration ) {
7907
- if( isset( $duration['week'] ) ||
7908
- isset( $duration['day'] ) ||
7909
- isset( $duration['hour'] ) ||
7910
- isset( $duration['min'] ) ||
7911
- isset( $duration['sec'] ))
7912
- $ok = TRUE;
7913
- else
7914
- return;
7915
- if( isset( $duration['week'] ) && ( 0 < $duration['week'] ))
7916
- return 'P'.$duration['week'].'W';
7917
- $output = 'P';
7918
- if( isset($duration['day'] ) && ( 0 < $duration['day'] ))
7919
- $output .= $duration['day'].'D';
7920
- if(( isset( $duration['hour']) && ( 0 < $duration['hour'] )) ||
7921
- ( isset( $duration['min']) && ( 0 < $duration['min'] )) ||
7922
- ( isset( $duration['sec']) && ( 0 < $duration['sec'] )))
7923
- $output .= 'T';
7924
- $output .= ( isset( $duration['hour']) && ( 0 < $duration['hour'] )) ? $duration['hour'].'H' : '';
7925
- $output .= ( isset( $duration['min']) && ( 0 < $duration['min'] )) ? $duration['min']. 'M' : '';
7926
- $output .= ( isset( $duration['sec']) && ( 0 < $duration['sec'] )) ? $duration['sec']. 'S' : '';
7927
- if( 'P' == $output )
7928
- $output = 'PT0S';
7929
- return $output;
7930
- }
7931
- /**
7932
- * checks if input array contains a date
7933
  *
7934
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7935
  * @since 2.11.8 - 2012-01-20
@@ -7954,7 +7823,7 @@ class iCalUtilityFunctions {
7954
  if(( isset( $input[0] ) && isset( $input[1] ) && isset( $input[2] )) &&
7955
  checkdate( (int) $input[1], (int) $input[2], (int) $input[0] ))
7956
  return TRUE;
7957
- $input = iCalUtilityFunctions::_date_time_string( $input[1].'/'.$input[2].'/'.$input[0], 3 ); // m - d - Y
7958
  if( isset( $input['year'] ) && isset( $input['month'] ) && isset( $input['day'] ))
7959
  return checkdate( (int) $input['month'], (int) $input['day'], (int) $input['year'] );
7960
  return FALSE;
@@ -7971,10 +7840,10 @@ class iCalUtilityFunctions {
7971
  return ( is_array( $input ) && isset( $input['timestamp'] )) ? TRUE : FALSE ;
7972
  }
7973
  /**
7974
- * controll if input string contains trailing UTC offset
7975
  *
7976
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7977
- * @since 2.4.16 - 2008-10-19
7978
  * @param string $input
7979
  * @return bool
7980
  */
@@ -7984,11 +7853,11 @@ class iCalUtilityFunctions {
7984
  return TRUE;
7985
  elseif(( 5 <= strlen( $input )) &&
7986
  ( in_array( substr( $input, -5, 1 ), array( '+', '-' ))) &&
7987
- ( '0000' < substr( $input, -4 )) && ( '9999' >= substr( $input, -4 )))
7988
  return TRUE;
7989
  elseif(( 7 <= strlen( $input )) &&
7990
  ( in_array( substr( $input, -7, 1 ), array( '+', '-' ))) &&
7991
- ( '000000' < substr( $input, -6 )) && ( '999999' >= substr( $input, -6 )))
7992
  return TRUE;
7993
  return FALSE;
7994
  }
@@ -7997,13 +7866,11 @@ class iCalUtilityFunctions {
7997
  * matching (MS) UCT offset and time zone descriptors
7998
  *
7999
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8000
- * @since 2.12.1 - 2012-04-06
8001
  * @param string $timezone, input/output variable reference
8002
  * @return bool
8003
  */
8004
  public static function ms2phpTZ( & $timezone ) {
8005
- if( substr( phpversion(), 0, 3 ) < '5.2' )
8006
- return FALSE;
8007
  if( empty( $timezone ))
8008
  return FALSE;
8009
  $search = str_replace( '"', '', $timezone );
@@ -8064,7 +7931,7 @@ class iCalUtilityFunctions {
8064
  return FALSE;
8065
  }
8066
  /**
8067
- * transform offset in seconds to [-/+]hhmm[ss]
8068
  *
8069
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8070
  * @since 2011-05-02
@@ -8101,9 +7968,27 @@ class iCalUtilityFunctions {
8101
  return $prefix.$output;
8102
  }
8103
  /**
8104
- * remakes a recur pattern to an array of dates
8105
  *
8106
  * if missing, UNTIL is set 1 year from startdate (emergency break)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8107
  *
8108
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8109
  * @since 2.10.19 - 2011-10-31
@@ -8112,7 +7997,7 @@ class iCalUtilityFunctions {
8112
  * @param array $wdate, component start date
8113
  * @param array $startdate, start date
8114
  * @param array $enddate, optional
8115
- * @return array of recurrence (start-)dates as index
8116
  * @todo BYHOUR, BYMINUTE, BYSECOND, WEEKLY at year end/start
8117
  */
8118
  public static function _recur2date( & $result, $recur, $wdate, $startdate, $enddate=FALSE ) {
@@ -8510,7 +8395,7 @@ class iCalUtilityFunctions {
8510
  * convert input format for exrule and rrule to internal format
8511
  *
8512
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8513
- * @since 2.11.15 - 2012-01-31
8514
  * @param array $rexrule
8515
  * @return array
8516
  */
@@ -8524,14 +8409,21 @@ class iCalUtilityFunctions {
8524
  $input[$rexrulelabel] = $rexrulevalue;
8525
  else {
8526
  iCalUtilityFunctions::_strDate2arr( $rexrulevalue );
8527
- if( iCalUtilityFunctions::_isArrayTimestampDate( $rexrulevalue )) // timestamp, always date-time
8528
- $input[$rexrulelabel] = iCalUtilityFunctions::_timestamp2date( $rexrulevalue, 6 );
8529
- elseif( iCalUtilityFunctions::_isArrayDate( $rexrulevalue )) { // date or date-time
8530
- $parno = ( isset( $rexrulevalue['hour'] ) || isset( $rexrulevalue[4] )) ? 6 : 3;
8531
- $input[$rexrulelabel] = iCalUtilityFunctions::_date_time_array( $rexrulevalue, $parno );
8532
- }
8533
- elseif( 8 <= strlen( trim( $rexrulevalue ))) { // ex. textual datetime/date 2006-08-03 10:12:18
8534
- $input[$rexrulelabel] = iCalUtilityFunctions::_date_time_string( $rexrulevalue );
 
 
 
 
 
 
 
8535
  unset( $input['$rexrulelabel']['unparsedtext'] );
8536
  }
8537
  if(( 3 < count( $input[$rexrulelabel] )) && !isset( $input[$rexrulelabel]['tz'] ))
@@ -8593,18 +8485,18 @@ class iCalUtilityFunctions {
8593
  * convert format for input date to internal date with parameters
8594
  *
8595
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8596
- * @since 2.11.8 - 2012-03-18
8597
- * @param mixed $year
8598
- * @param mixed $month optional
8599
- * @param int $day optional
8600
- * @param int $hour optional
8601
- * @param int $min optional
8602
- * @param int $sec optional
8603
- * @param string $tz optional
8604
- * @param array $params optional
8605
- * @param string $caller optional
8606
  * @param string $objName optional
8607
- * @param string $tzid optional
8608
  * @return array
8609
  */
8610
  public static function _setDate( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE, $caller=null, $objName=null, $tzid=FALSE ) {
@@ -8612,55 +8504,89 @@ class iCalUtilityFunctions {
8612
  $localtime = (( 'dtstart' == $caller ) && in_array( $objName, array( 'vtimezone', 'standard', 'daylight' ))) ? TRUE : FALSE;
8613
  iCalUtilityFunctions::_strDate2arr( $year );
8614
  if( iCalUtilityFunctions::_isArrayDate( $year )) {
8615
- if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
8616
- $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
8617
- if( isset( $input['params']['TZID'] )) {
8618
- $input['params']['VALUE'] = 'DATE-TIME';
8619
- unset( $year['tz'] );
 
 
 
 
 
 
 
8620
  }
8621
- $hitval = ( isset( $year['tz'] ) || isset( $year[6] )) ? 7 : 6;
 
8622
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval );
8623
- $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3, count( $year ), $parno );
8624
- $input['value'] = iCalUtilityFunctions::_date_time_array( $year, $parno );
8625
- }
 
 
 
 
 
 
 
 
 
8626
  elseif( iCalUtilityFunctions::_isArrayTimestampDate( $year )) {
8627
  if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
8628
  $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
8629
- if( isset( $input['params']['TZID'] )) {
8630
- $input['params']['VALUE'] = 'DATE-TIME';
8631
- unset( $year['tz'] );
8632
- }
8633
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3 );
8634
- $hitval = ( isset( $year['tz'] )) ? 7 : 6;
8635
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno );
8636
- $input['value'] = iCalUtilityFunctions::_timestamp2date( $year, $parno );
8637
- }
8638
- elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18
8639
- if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
8640
- $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
8641
- if( isset( $input['params']['TZID'] )) {
8642
- $input['params']['VALUE'] = 'DATE-TIME';
8643
- $parno = 6;
8644
  }
8645
- elseif( $tzid && iCalUtilityFunctions::_isOffset( substr( $year, -7 ))) {
8646
- if(( in_array( substr( $year, -5, 1 ), array( '+', '-' ))) &&
8647
- ( '0000' < substr( $year, -4 )) && ( '9999' >= substr( $year, -4 )))
8648
- $year = substr( $year, 0, ( strlen( $year ) - 5 ));
8649
- elseif(( in_array( substr( $input, -7, 1 ), array( '+', '-' ))) &&
8650
- ( '000000' < substr( $input, -6 )) && ( '999999' >= substr( $input, -6 )))
8651
- $year = substr( $year, 0, ( strlen( $year ) - 7 ));
8652
- $parno = 6;
8653
  }
 
 
 
 
 
 
 
 
8654
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7, $parno );
8655
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3, $parno, $parno );
8656
- $input['value'] = iCalUtilityFunctions::_date_time_string( $year, $parno );
8657
  unset( $input['value']['unparsedtext'] );
8658
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8659
  else {
8660
- if( is_array( $params )) {
8661
- if( $localtime ) unset ( $params['VALUE'], $params['TZID'] );
8662
  $input['params'] = iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' ));
8663
- }
8664
  elseif( is_array( $tz )) {
8665
  $input['params'] = iCalUtilityFunctions::_setParams( $tz, array( 'VALUE' => 'DATE-TIME' ));
8666
  $tz = FALSE;
@@ -8669,12 +8595,18 @@ class iCalUtilityFunctions {
8669
  $input['params'] = iCalUtilityFunctions::_setParams( $hour, array( 'VALUE' => 'DATE-TIME' ));
8670
  $hour = $min = $sec = $tz = FALSE;
8671
  }
8672
- if( isset( $input['params']['TZID'] )) {
8673
- $tz = null;
8674
- $input['params']['VALUE'] = 'DATE-TIME';
 
 
 
 
 
 
8675
  }
8676
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3 );
8677
- $hitval = ( !empty( $tz )) ? 7 : 6;
8678
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno, $parno );
8679
  $input['value'] = array( 'year' => $year, 'month' => $month, 'day' => $day );
8680
  if( 3 != $parno ) {
@@ -8683,49 +8615,68 @@ class iCalUtilityFunctions {
8683
  $input['value']['sec'] = ( $sec ) ? $sec : '0';
8684
  if( !empty( $tz ))
8685
  $input['value']['tz'] = $tz;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8686
  }
8687
- }
8688
- if( 3 == $parno ) {
8689
  $input['params']['VALUE'] = 'DATE';
8690
- unset( $input['value']['tz'] );
8691
- unset( $input['params']['TZID'] );
8692
  }
8693
- elseif( isset( $input['params']['TZID'] ))
8694
- unset( $input['value']['tz'] );
8695
- if( $localtime )
8696
- unset( $input['value']['tz'], $input['params']['TZID'] );
8697
- elseif(( !isset( $input['params']['VALUE'] ) || ( $input['params']['VALUE'] != 'DATE' )) && !isset( $input['params']['TZID'] ) && $tzid )
8698
- $input['params']['TZID'] = $tzid;
8699
- if( isset( $input['value']['tz'] ))
8700
- $input['value']['tz'] = (string) $input['value']['tz'];
8701
- if( !empty( $input['value']['tz'] ) && ( 'Z' != $input['value']['tz'] ) && // real time zone in tz to TZID
8702
- ( !iCalUtilityFunctions::_isOffset( $input['value']['tz'] ))) {
8703
- $input['params']['TZID'] = $input['value']['tz'];
8704
- unset( $input['value']['tz'] );
8705
- }
8706
- if( isset( $input['params']['TZID'] ) && !empty( $input['params']['TZID'] )) {
8707
- if(( 'Z' != $input['params']['TZID'] ) && iCalUtilityFunctions::_isOffset( $input['params']['TZID'] )) { // utc offset in TZID to tz
8708
- $input['value']['tz'] = $input['params']['TZID'];
8709
  unset( $input['params']['TZID'] );
8710
  }
8711
- elseif( in_array( strtoupper( $input['params']['TZID'] ), array( 'GMT', 'UTC', 'Z' ))) { // time zone Z
 
 
 
 
8712
  $input['value']['tz'] = 'Z';
8713
- unset( $input['params']['TZID'] );
 
 
8714
  }
 
 
8715
  }
 
 
8716
  return $input;
8717
  }
8718
  /**
8719
  * convert format for input date (UTC) to internal date with parameters
8720
  *
8721
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8722
- * @since 2.11.8 - 2012-01-19
8723
  * @param mixed $year
8724
- * @param mixed $month optional
8725
- * @param int $day optional
8726
- * @param int $hour optional
8727
- * @param int $min optional
8728
- * @param int $sec optional
8729
  * @param array $params optional
8730
  * @return array
8731
  */
@@ -8733,17 +8684,26 @@ class iCalUtilityFunctions {
8733
  $input = null;
8734
  iCalUtilityFunctions::_strDate2arr( $year );
8735
  if( iCalUtilityFunctions::_isArrayDate( $year )) {
8736
- $input['value'] = iCalUtilityFunctions::_date_time_array( $year, 7 );
8737
- $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
 
 
 
 
 
 
 
 
8738
  }
8739
  elseif( iCalUtilityFunctions::_isArrayTimestampDate( $year )) {
 
8740
  $input['value'] = iCalUtilityFunctions::_timestamp2date( $year, 7 );
8741
- $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
8742
  }
8743
  elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18
8744
- $input['value'] = iCalUtilityFunctions::_date_time_string( $year, 7 );
8745
  unset( $input['value']['unparsedtext'] );
8746
- $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
8747
  }
8748
  else {
8749
  $input['value'] = array( 'year' => $year
@@ -8752,27 +8712,23 @@ class iCalUtilityFunctions {
8752
  , 'hour' => $hour
8753
  , 'min' => $min
8754
  , 'sec' => $sec );
 
 
 
 
 
 
 
 
 
 
8755
  $input['params'] = iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' ));
8756
  }
8757
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7 ); // remove default
8758
- if( !isset( $input['value']['hour'] ))
8759
- $input['value']['hour'] = 0;
8760
- if( !isset( $input['value']['min'] ))
8761
- $input['value']['min'] = 0;
8762
- if( !isset( $input['value']['sec'] ))
8763
- $input['value']['sec'] = 0;
8764
- if( isset( $input['params']['TZID'] ) && !empty( $input['params']['TZID'] )) {
8765
- if(( 'Z' != $input['params']['TZID'] ) && iCalUtilityFunctions::_isOffset( $input['params']['TZID'] )) { // utc offset in TZID to tz
8766
- $input['value']['tz'] = $input['params']['TZID'];
8767
- unset( $input['params']['TZID'] );
8768
- }
8769
- elseif( in_array( strtoupper( $input['params']['TZID'] ), array( 'GMT', 'UTC', 'Z' ))) { // time zone Z
8770
- $input['value']['tz'] = 'Z';
8771
- unset( $input['params']['TZID'] );
8772
- }
8773
- }
8774
- if( !isset( $input['value']['tz'] ) || !iCalUtilityFunctions::_isOffset( $input['value']['tz'] ))
8775
- $input['value']['tz'] = 'Z';
8776
  return $input;
8777
  }
8778
  /**
@@ -8841,21 +8797,24 @@ class iCalUtilityFunctions {
8841
  * step date, return updated date, array and timpstamp
8842
  *
8843
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8844
- * @since 2.4.16 - 2008-10-18
8845
  * @param array $date, date to step
8846
- * @param int $timestamp
8847
  * @param array $step, default array( 'day' => 1 )
8848
  * @return void
8849
  */
8850
  public static function _stepdate( &$date, &$timestamp, $step=array( 'day' => 1 )) {
 
 
 
8851
  foreach( $step as $stepix => $stepvalue )
8852
  $date[$stepix] += $stepvalue;
8853
- $timestamp = iCalUtilityFunctions::_date2timestamp( $date );
8854
- $date = iCalUtilityFunctions::_timestamp2date( $timestamp, 6 );
8855
- foreach( $date as $k => $v ) {
8856
- if( ctype_digit( $v ))
8857
- $date[$k] = (int) $v;
8858
- }
8859
  }
8860
  /**
8861
  * convert a date from specific string to array format
@@ -8877,11 +8836,11 @@ class iCalUtilityFunctions {
8877
  $work = str_replace( '/', '', $work );
8878
  if( !ctype_digit( substr( $work, 0, 8 )))
8879
  return FALSE;
8880
- if( !checkdate( (int) substr( $work, 4, 2 ), (int) substr( $work, 6, 2 ), (int) substr( $work, 0, 4 )))
 
 
 
8881
  return FALSE;
8882
- $temp = array( 'year' => substr( $work, 0, 4 )
8883
- , 'month' => substr( $work, 4, 2 )
8884
- , 'day' => substr( $work, 6, 2 ));
8885
  if( 8 == strlen( $work )) {
8886
  $input = $temp;
8887
  return TRUE;
@@ -8903,7 +8862,7 @@ class iCalUtilityFunctions {
8903
  return FALSE;
8904
  if( ctype_digit( substr( $work, 4, 2 ))) {
8905
  $temp['sec'] = substr( $work, 4, 2 );
8906
- if(( 0 > $temp['sec'] ) || ( $temp['sec'] > 59 ))
8907
  return FALSE;
8908
  $len = 6;
8909
  }
@@ -8917,34 +8876,168 @@ class iCalUtilityFunctions {
8917
  return TRUE;
8918
  }
8919
  /**
8920
- * convert timestamp to date array
8921
  *
8922
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8923
- * @since 2.4.16 - 2008-11-01
8924
- * @param mixed $timestamp
8925
- * @param int $parno
 
 
8926
  * @return array
8927
  */
8928
- public static function _timestamp2date( $timestamp, $parno=6 ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8929
  if( is_array( $timestamp )) {
8930
- if(( 7 == $parno ) && !empty( $timestamp['tz'] ))
8931
- $tz = $timestamp['tz'];
8932
  $timestamp = $timestamp['timestamp'];
8933
  }
8934
- $output = array( 'year' => date( 'Y', $timestamp )
8935
- , 'month' => date( 'm', $timestamp )
8936
- , 'day' => date( 'd', $timestamp ));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8937
  if( 3 != $parno ) {
8938
- $output['hour'] = date( 'H', $timestamp );
8939
- $output['min'] = date( 'i', $timestamp );
8940
- $output['sec'] = date( 's', $timestamp );
8941
- if( isset( $tz ))
8942
- $output['tz'] = $tz;
8943
  }
8944
  return $output;
8945
  }
8946
  /**
8947
- * convert timestamp to duration in array format
8948
  *
8949
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8950
  * @since 2.6.23 - 2010-10-23
@@ -8967,41 +9060,39 @@ class iCalUtilityFunctions {
8967
  * transforms a dateTime from a timezone to another using PHP DateTime and DateTimeZone class (PHP >= PHP 5.2.0)
8968
  *
8969
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8970
- * @since 2.12.1 - 2012-04-1
8971
  * @param mixed $date, date to alter
8972
- * @param string $tzFrom, PHP valid old timezone
8973
- * @param string $tzTo, PHP valid new timezone, default 'UTC'
8974
  * @param string $format, date output format, default 'Ymd\THis'
8975
  * @return bool
8976
  */
8977
  public static function transformDateTime( & $date, $tzFrom, $tzTo='UTC', $format = 'Ymd\THis' ) {
8978
- if( substr( phpversion(), 0, 3 ) < '5.2' )
8979
- return FALSE;
8980
- if( is_array( $date ) && isset( $date['timestamp'] ))
8981
- $timestamp = $date['timestamp'];
8982
- elseif( iCalUtilityFunctions::_isArrayDate( $date )) {
8983
- if(isset( $date['tz'] ))
8984
- unset( $date['tz'] );
8985
- $date = iCalUtilityFunctions::_format_date_time( iCalUtilityFunctions::_date_time_array( $date ));
 
 
 
 
 
8986
  if( 'Z' == substr( $date, -1 ))
8987
  $date = substr( $date, 0, ( strlen( $date ) - 2 ));
8988
- if( FALSE === ( $timestamp = strtotime( $date )))
8989
- return FALSE;
8990
- }
8991
- elseif( FALSE === ( $timestamp = @strtotime( $date )))
8992
- return FALSE;
8993
- try {
8994
- $d = new DateTime( date( 'Y-m-d H:i:s', $timestamp ), new DateTimeZone( $tzFrom ));
8995
- $d->setTimezone( new DateTimeZone( $tzTo ));
8996
- }
8997
- catch (Exception $e) {
8998
- return FALSE;
8999
  }
 
 
9000
  $date = $d->format( $format );
9001
  return TRUE;
9002
  }
9003
  /**
9004
- * convert (numeric) local time offset, ("+" / "-")HHmm[ss], to seconds correcting localtime to GMT
9005
  *
9006
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
9007
  * @since 2.11.4 - 2012-01-11
@@ -9011,10 +9102,10 @@ class iCalUtilityFunctions {
9011
  public static function _tz2offset( $tz ) {
9012
  $tz = trim( (string) $tz );
9013
  $offset = 0;
9014
- if((( 5 != strlen( $tz )) && ( 7 != strlen( $tz ))) ||
9015
  (( '+' != substr( $tz, 0, 1 )) && ( '-' != substr( $tz, 0, 1 ))) ||
9016
  (( '0000' >= substr( $tz, 1, 4 )) && ( '9999' < substr( $tz, 1, 4 ))) ||
9017
- (( 7 == strlen( $tz )) && ( '00' > substr( $tz, 5, 2 )) && ( '99' < substr( $tz, 5, 2 ))))
9018
  return $offset;
9019
  $hours2sec = (int) substr( $tz, 1, 2 ) * 3600;
9020
  $min2sec = (int) substr( $tz, 3, 2 ) * 60;
@@ -9168,7 +9259,7 @@ function iCal2vCards( & $calendar, $version='2.1', $directory=FALSE, $ext='vcf'
9168
  * format iCal XML output, rfc6321, using PHP SimpleXMLElement
9169
  *
9170
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
9171
- * @since 2.12.3 - 2012-04-19
9172
  * @param object $calendar, iCalcreator vcalendar instance reference
9173
  * @return string
9174
  */
@@ -9192,72 +9283,28 @@ function iCal2XML( & $calendar ) {
9192
  /** prepare to fix components with properties */
9193
  $components = $vcalendar->addChild( 'components' );
9194
  $comps = array( 'vtimezone', 'vevent', 'vtodo', 'vjournal', 'vfreebusy' );
9195
- $eventProps = array( 'dtstamp', 'dtstart', 'uid',
9196
- 'class', 'created', 'description', 'geo', 'last-modified', 'location', 'organizer', 'priority',
9197
- 'sequence', 'status', 'summary', 'transp', 'url', 'recurrence-id', 'rrule', 'dtend', 'duration',
9198
- 'attach', 'attendee', 'categories', 'comment', 'contact', 'exdate', 'request-status', 'related-to', 'resources', 'rdate',
9199
- 'x-prop' );
9200
- $todoProps = array( 'dtstamp', 'uid',
9201
- 'class', 'completed', 'created', 'description', 'geo', 'last-modified', 'location', 'organizer', 'percent-complete', 'priority',
9202
- 'recurrence-id', 'sequence', 'status', 'summary', 'url', 'rrule', 'dtstart', 'due', 'duration',
9203
- 'attach', 'attendee', 'categories', 'comment', 'contact', 'exdate', 'request-status', 'related-to', 'resources', 'rdate',
9204
- 'x-prop' );
9205
- $journalProps = array( 'dtstamp', 'uid',
9206
- 'class', 'created', 'dtstart', 'last-modified', 'organizer', 'recurrence-id', 'sequence', 'status', 'summary', 'url', 'rrule',
9207
- 'attach', 'attendee', 'categories', 'comment', 'contact',
9208
- 'description',
9209
- 'exdate', 'related-to', 'rdate', 'request-status',
9210
- 'x-prop' );
9211
- $freebusyProps = array( 'dtstamp', 'uid',
9212
- 'contact', 'dtstart', 'dtend', 'duration', 'organizer', 'url',
9213
- 'attendee', 'comment', 'freebusy', 'request-status',
9214
- 'x-prop' );
9215
- $timezoneProps = array( 'tzid',
9216
- 'last-modified', 'tzurl',
9217
- 'x-prop' );
9218
- $alarmProps = array( 'action', 'description', 'trigger', 'summary',
9219
- 'attendee',
9220
- 'duration', 'repeat', 'attach',
9221
- 'x-prop' );
9222
- $stddghtProps = array( 'dtstart', 'tzoffsetto', 'tzoffsetfrom',
9223
- 'rrule',
9224
- 'comment', 'rdate', 'tzname',
9225
- 'x-prop' );
9226
  foreach( $comps as $compName ) {
9227
  switch( $compName ) {
9228
  case 'vevent':
9229
- $props = & $eventProps;
9230
- $subComps = array( 'valarm' );
9231
- $subCompProps = & $alarmProps;
9232
- break;
9233
  case 'vtodo':
9234
- $props = & $todoProps;
9235
  $subComps = array( 'valarm' );
9236
- $subCompProps = & $alarmProps;
9237
  break;
9238
  case 'vjournal':
9239
- $props = & $journalProps;
9240
- $subComps = array();
9241
- $subCompProps = array();
9242
- break;
9243
  case 'vfreebusy':
9244
- $props = & $freebusyProps;
9245
  $subComps = array();
9246
- $subCompProps = array();
9247
  break;
9248
  case 'vtimezone':
9249
- $props = & $timezoneProps;
9250
  $subComps = array( 'standard', 'daylight' );
9251
- $subCompProps = & $stddghtProps;
9252
  break;
9253
  } // end switch( $compName )
9254
  /** fix component properties */
9255
  while( FALSE !== ( $component = $calendar->getComponent( $compName ))) {
9256
  $child = $components->addChild( $compName );
9257
  $properties = $child->addChild( 'properties' );
9258
- $langComp = $component->getConfig( 'language' );
 
9259
  foreach( $props as $prop ) {
9260
- switch( $prop ) {
9261
  case 'attach': // may occur multiple times, below
9262
  while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) {
9263
  $type = ( isset( $content['params']['VALUE'] ) && ( 'BINARY' == $content['params']['VALUE'] )) ? 'binary' : 'uri';
@@ -9280,31 +9327,17 @@ function iCal2XML( & $calendar ) {
9280
  while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) {
9281
  $type = ( isset( $content['params']['VALUE'] ) && ( 'DATE' == $content['params']['VALUE'] )) ? 'date' : 'date-time';
9282
  unset( $content['params']['VALUE'] );
9283
- foreach( $content['value'] as & $exDate ) {
9284
- if( ( isset( $exDate['tz'] ) && // fix UTC-date if offset set
9285
- iCalUtilityFunctions::_isOffset( $exDate['tz'] ) &&
9286
- ( 'Z' != $exDate['tz'] ))
9287
- || ( isset( $content['params']['TZID'] ) &&
9288
- iCalUtilityFunctions::_isOffset( $content['params']['TZID'] ) &&
9289
- ( 'Z' != $content['params']['TZID'] ))) {
9290
- $offset = isset( $exDate['tz'] ) ? $exDate['tz'] : $content['params']['TZID'];
9291
- $date = mktime( (int) $exDate['hour'],
9292
- (int) $exDate['min'],
9293
- (int) ($exDate['sec'] + iCalUtilityFunctions::_tz2offset( $offset )),
9294
- (int) $exDate['month'],
9295
- (int) $exDate['day'],
9296
- (int) $exDate['year'] );
9297
- unset( $exDate['tz'] );
9298
- $exDate = iCalUtilityFunctions::_date_time_string( date( 'Ymd\THis\Z', $date ), 6 );
9299
- unset( $exDate['unparsedtext'] );
9300
- }
9301
- }
9302
  _addXMLchild( $properties, $prop, $type, $content['value'], $content['params'] );
9303
  }
9304
  break;
9305
  case 'freebusy':
9306
- while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE )))
 
 
 
 
9307
  _addXMLchild( $properties, $prop, 'period', $content['value'], $content['params'] );
 
9308
  break;
9309
  case 'request-status':
9310
  while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) {
@@ -9326,67 +9359,6 @@ function iCal2XML( & $calendar ) {
9326
  elseif( 'PERIOD' == $content['params']['VALUE'] )
9327
  $type = 'period';
9328
  }
9329
- if( 'period' == $type ) {
9330
- foreach( $content['value'] as & $rDates ) {
9331
- if( ( isset( $rDates[0]['tz'] ) && // fix UTC-date if offset set
9332
- iCalUtilityFunctions::_isOffset( $rDates[0]['tz'] ) &&
9333
- ( 'Z' != $rDates[0]['tz'] ))
9334
- || ( isset( $content['params']['TZID'] ) &&
9335
- iCalUtilityFunctions::_isOffset( $content['params']['TZID'] ) &&
9336
- ( 'Z' != $content['params']['TZID'] ))) {
9337
- $offset = isset( $rDates[0]['tz'] ) ? $rDates[0]['tz'] : $content['params']['TZID'];
9338
- $date = mktime( (int) $rDates[0]['hour'],
9339
- (int) $rDates[0]['min'],
9340
- (int) ($rDates[0]['sec'] + iCalUtilityFunctions::_tz2offset( $offset )),
9341
- (int) $rDates[0]['month'],
9342
- (int) $rDates[0]['day'],
9343
- (int) $rDates[0]['year'] );
9344
- unset( $rDates[0]['tz'] );
9345
- $rDates[0] = iCalUtilityFunctions::_date_time_string( date( 'Ymd\THis\Z', $date ), 6 );
9346
- unset( $rDates[0]['unparsedtext'] );
9347
- }
9348
- if( isset( $rDates[1]['year'] )) {
9349
- if( ( isset( $rDates[1]['tz'] ) && // fix UTC-date if offset set
9350
- iCalUtilityFunctions::_isOffset( $rDates[1]['tz'] ) &&
9351
- ( 'Z' != $rDates[1]['tz'] ))
9352
- || ( isset( $content['params']['TZID'] ) &&
9353
- iCalUtilityFunctions::_isOffset( $content['params']['TZID'] ) &&
9354
- ( 'Z' != $content['params']['TZID'] ))) {
9355
- $offset = isset( $rDates[1]['tz'] ) ? $rDates[1]['tz'] : $content['params']['TZID'];
9356
- $date = mktime( (int) $rDates[1]['hour'],
9357
- (int) $rDates[1]['min'],
9358
- (int) ($rDates[1]['sec'] + iCalUtilityFunctions::_tz2offset( $offset )),
9359
- (int) $rDates[1]['month'],
9360
- (int) $rDates[1]['day'],
9361
- (int) $rDates[1]['year'] );
9362
- unset( $rDates[1]['tz'] );
9363
- $rDates[1] = iCalUtilityFunctions::_date_time_string( date( 'Ymd\THis\Z', $date ), 6 );
9364
- unset( $rDates[1]['unparsedtext'] );
9365
- }
9366
- }
9367
- }
9368
- }
9369
- elseif( 'date-time' == $type ) {
9370
- foreach( $content['value'] as & $rDate ) {
9371
- if( ( isset( $rDate['tz'] ) && // fix UTC-date if offset set
9372
- iCalUtilityFunctions::_isOffset( $rDate['tz'] ) &&
9373
- ( 'Z' != $rDate['tz'] ))
9374
- || ( isset( $content['params']['TZID'] ) &&
9375
- iCalUtilityFunctions::_isOffset( $content['params']['TZID'] ) &&
9376
- ( 'Z' != $content['params']['TZID'] ))) {
9377
- $offset = isset( $rDate['tz'] ) ? $rDate['tz'] : $content['params']['TZID'];
9378
- $date = mktime( (int) $rDate['hour'],
9379
- (int) $rDate['min'],
9380
- (int) ($rDate['sec'] + iCalUtilityFunctions::_tz2offset( $offset )),
9381
- (int) $rDate['month'],
9382
- (int) $rDate['day'],
9383
- (int) $rDate['year'] );
9384
- unset( $rDate['tz'] );
9385
- $rDate = iCalUtilityFunctions::_date_time_string( date( 'Ymd\THis\Z', $date ), 6 );
9386
- unset( $rDate['unparsedtext'] );
9387
- }
9388
- }
9389
- }
9390
  unset( $content['params']['VALUE'] );
9391
  _addXMLchild( $properties, $prop, $type, $content['value'], $content['params'] );
9392
  }
@@ -9421,37 +9393,7 @@ function iCal2XML( & $calendar ) {
9421
  case 'due':
9422
  case 'recurrence-id':
9423
  if( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) {
9424
- if( isset( $content['params']['VALUE'] ) && ( 'DATE' == $content['params']['VALUE'] )) {
9425
- $type = 'date';
9426
- unset( $content['value']['hour'], $content['value']['min'], $content['value']['sec'] );
9427
- }
9428
- else {
9429
- $type = 'date-time';
9430
- if( isset( $utcDate ) && !isset( $content['value']['tz'] ))
9431
- $content['value']['tz'] = 'Z';
9432
- if( ( isset( $content['value']['tz'] ) && // fix UTC-date if offset set
9433
- iCalUtilityFunctions::_isOffset( $content['value']['tz'] ) &&
9434
- ( 'Z' != $content['value']['tz'] ))
9435
- || ( isset( $content['params']['TZID'] ) &&
9436
- iCalUtilityFunctions::_isOffset( $content['params']['TZID'] ) &&
9437
- ( 'Z' != $content['params']['TZID'] ))) {
9438
- $offset = isset( $content['value']['tz'] ) ? $content['value']['tz'] : $content['params']['TZID'];
9439
- $date = mktime( (int) $content['value']['hour'],
9440
- (int) $content['value']['min'],
9441
- (int) ($content['value']['sec'] + iCalUtilityFunctions::_tz2offset( $offset )),
9442
- (int) $content['value']['month'],
9443
- (int) $content['value']['day'],
9444
- (int) $content['value']['year'] );
9445
- unset( $content['value']['tz'], $content['params']['TZID'] );
9446
- $content['value'] = iCalUtilityFunctions::_date_time_string( date( 'Ymd\THis\Z', $date ), 6 );
9447
- unset( $content['value']['unparsedtext'] );
9448
- }
9449
- elseif( isset( $content['value']['tz'] ) && !empty( $content['value']['tz'] ) &&
9450
- ( 'Z' != $content['value']['tz'] ) && !isset( $content['params']['TZID'] )) {
9451
- $content['params']['TZID'] = $content['value']['tz'];
9452
- unset( $content['value']['tz'] );
9453
- }
9454
- }
9455
  unset( $content['params']['VALUE'] );
9456
  if(( isset( $content['params']['TZID'] ) && empty( $content['params']['TZID'] )) || @is_null( $content['params']['TZID'] ))
9457
  unset( $content['params']['TZID'] );
@@ -9460,8 +9402,11 @@ function iCal2XML( & $calendar ) {
9460
  unset( $utcDate );
9461
  break;
9462
  case 'duration':
9463
- if( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE )))
 
 
9464
  _addXMLchild( $properties, $prop, 'duration', $content['value'], $content['params'] );
 
9465
  break;
9466
  case 'rrule':
9467
  while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE )))
@@ -9515,11 +9460,12 @@ function iCal2XML( & $calendar ) {
9515
  /** fix subComponent properties, if any */
9516
  foreach( $subComps as $subCompName ) {
9517
  while( FALSE !== ( $subcomp = $component->getComponent( $subCompName ))) {
9518
- $child2 = $child->addChild( $subCompName );
9519
- $properties = $child2->addChild( 'properties' );
9520
- $langComp = $subcomp->getConfig( 'language' );
 
9521
  foreach( $subCompProps as $prop ) {
9522
- switch( $prop ) {
9523
  case 'attach': // may occur multiple times, below
9524
  while( FALSE !== ( $content = $subcomp->getProperty( $prop, FALSE, TRUE ))) {
9525
  $type = ( isset( $content['params']['VALUE'] ) && ( 'BINARY' == $content['params']['VALUE'] )) ? 'binary' : 'uri';
@@ -9559,67 +9505,6 @@ function iCal2XML( & $calendar ) {
9559
  elseif( 'PERIOD' == $content['params']['VALUE'] )
9560
  $type = 'period';
9561
  }
9562
- if( 'period' == $type ) {
9563
- foreach( $content['value'] as & $rDates ) {
9564
- if( ( isset( $rDates[0]['tz'] ) && // fix UTC-date if offset set
9565
- iCalUtilityFunctions::_isOffset( $rDates[0]['tz'] ) &&
9566
- ( 'Z' != $rDates[0]['tz'] ))
9567
- || ( isset( $content['params']['TZID'] ) &&
9568
- iCalUtilityFunctions::_isOffset( $content['params']['TZID'] ) &&
9569
- ( 'Z' != $content['params']['TZID'] ))) {
9570
- $offset = isset( $rDates[0]['tz'] ) ? $rDates[0]['tz'] : $content['params']['TZID'];
9571
- $date = mktime( (int) $rDates[0]['hour'],
9572
- (int) $rDates[0]['min'],
9573
- (int) ($rDates[0]['sec'] + iCalUtilityFunctions::_tz2offset( $offset )),
9574
- (int) $rDates[0]['month'],
9575
- (int) $rDates[0]['day'],
9576
- (int) $rDates[0]['year'] );
9577
- unset( $rDates[0]['tz'] );
9578
- $rDates[0] = iCalUtilityFunctions::_date_time_string( date( 'Ymd\THis\Z', $date ), 6 );
9579
- unset( $rDates[0]['unparsedtext'] );
9580
- }
9581
- if( isset( $rDates[1]['year'] )) {
9582
- if( ( isset( $rDates[1]['tz'] ) && // fix UTC-date if offset set
9583
- iCalUtilityFunctions::_isOffset( $rDates[1]['tz'] ) &&
9584
- ( 'Z' != $rDates[1]['tz'] ))
9585
- || ( isset( $content['params']['TZID'] ) &&
9586
- iCalUtilityFunctions::_isOffset( $content['params']['TZID'] ) &&
9587
- ( 'Z' != $content['params']['TZID'] ))) {
9588
- $offset = isset( $rDates[1]['tz'] ) ? $rDates[1]['tz'] : $content['params']['TZID'];
9589
- $date = mktime( (int) $rDates[1]['hour'],
9590
- (int) $rDates[1]['min'],
9591
- (int) ($rDates[1]['sec'] + iCalUtilityFunctions::_tz2offset( $offset )),
9592
- (int) $rDates[1]['month'],
9593
- (int) $rDates[1]['day'],
9594
- (int) $rDates[1]['year'] );
9595
- unset( $rDates[1]['tz'] );
9596
- $rDates[1] = iCalUtilityFunctions::_date_time_string( date( 'Ymd\THis\Z', $date ), 6 );
9597
- unset( $rDates[1]['unparsedtext'] );
9598
- }
9599
- }
9600
- }
9601
- }
9602
- elseif( 'date-time' == $type ) {
9603
- foreach( $content['value'] as & $rDate ) {
9604
- if( ( isset( $rDate['tz'] ) && // fix UTC-date if offset set
9605
- iCalUtilityFunctions::_isOffset( $rDate['tz'] ) &&
9606
- ( 'Z' != $rDate['tz'] ))
9607
- || ( isset( $content['params']['TZID'] ) &&
9608
- iCalUtilityFunctions::_isOffset( $content['params']['TZID'] ) &&
9609
- ( 'Z' != $content['params']['TZID'] ))) {
9610
- $offset = isset( $rDate['tz'] ) ? $rDate['tz'] : $content['params']['TZID'];
9611
- $date = mktime( (int) $rDate['hour'],
9612
- (int) $rDate['min'],
9613
- (int) ($rDate['sec'] + iCalUtilityFunctions::_tz2offset( $offset )),
9614
- (int) $rDate['month'],
9615
- (int) $rDate['day'],
9616
- (int) $rDate['year'] );
9617
- unset( $rDate['tz'] );
9618
- $rDate = iCalUtilityFunctions::_date_time_string( date( 'Ymd\THis\Z', $date ), 6 );
9619
- unset( $rDate['unparsedtext'] );
9620
- }
9621
- }
9622
- }
9623
  unset( $content['params']['VALUE'] );
9624
  _addXMLchild( $properties, $prop, $type, $content['value'], $content['params'] );
9625
  }
@@ -9661,8 +9546,11 @@ function iCal2XML( & $calendar ) {
9661
  isset( $content['value']['month'] ) &&
9662
  isset( $content['value']['day'] ))
9663
  $type = 'date-time';
9664
- else
9665
  $type = 'duration';
 
 
 
9666
  _addXMLchild( $properties, $prop, $type, $content['value'], $content['params'] );
9667
  }
9668
  break;
@@ -9687,7 +9575,7 @@ function iCal2XML( & $calendar ) {
9687
  * Add children to a SimpleXMLelement
9688
  *
9689
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
9690
- * @since 2.11.1 - 2012-01-16
9691
  * @param object $parent, reference to a SimpleXMLelement node
9692
  * @param string $name, new element node name
9693
  * @param string $type, content type, subelement(-s) name
@@ -9697,16 +9585,10 @@ function iCal2XML( & $calendar ) {
9697
  */
9698
  function _addXMLchild( & $parent, $name, $type, $content, $params=array()) {
9699
  /** create new child node */
9700
- $child = $parent->addChild( strtolower( $name ));
9701
- /** fix attributes */
9702
- if( is_array( $content ) && isset( $content['fbtype'] )) {
9703
- $params['FBTYPE'] = $content['fbtype'];
9704
- unset( $content['fbtype'] );
9705
- }
9706
  if( isset( $params['VALUE'] ))
9707
  unset( $params['VALUE'] );
9708
- if(( 'trigger' == $name ) && ( 'duration' == $type ) && ( TRUE !== $content['relatedStart'] ))
9709
- $params['RELATED'] = 'END';
9710
  if( !empty( $params )) {
9711
  $parameters = $child->addChild( 'parameters' );
9712
  foreach( $params as $param => $parVal ) {
@@ -9771,7 +9653,7 @@ function _addXMLchild( & $parent, $name, $type, $content, $params=array()) {
9771
  break;
9772
  case 'duration':
9773
  $output = (( 'trigger' == $name ) && ( FALSE !== $content['before'] )) ? '-' : '';
9774
- $v = $child->addChild( $type, $output.iCalUtilityFunctions::_format_duration( $content ) );
9775
  break;
9776
  case 'geo':
9777
  $v1 = $child->addChild( 'latitude', number_format( (float) $content['latitude'], 6, '.', '' ));
@@ -9796,7 +9678,7 @@ function _addXMLchild( & $parent, $name, $type, $content, $params=array()) {
9796
  $v2 = $v1->addChild( 'end', $str );
9797
  }
9798
  else
9799
- $v2 = $v1->addChild( 'duration', iCalUtilityFunctions::_format_duration( $period[1] ));
9800
  }
9801
  break;
9802
  case 'recur':
@@ -10180,8 +10062,10 @@ function _getXMLProperties( & $iCal, & $property ) {
10180
  $iCal->setProperty( $propName, $value, $params );
10181
  }
10182
  }
 
 
 
10183
  /**
10184
- * Additional functions to use with vtimezone components
10185
  * For use with
10186
  * iCalcreator (kigkonsult.se/iCalcreator/index.php)
10187
  * copyright (c) 2011 Yitzchok Lavi
@@ -10468,4 +10352,4 @@ function expandTimezoneDates($vtzc) {
10468
  }
10469
  }
10470
  return $tzdates;
10471
- }
1
  <?php
2
  /*********************************************************************************/
3
  /**
4
+ * iCalcreator v2.16.1
5
  * copyright (c) 2007-2012 Kjell-Inge Gustafsson kigkonsult
6
  * kigkonsult.se/iCalcreator/index.php
7
  * ical@kigkonsult.se
8
  *
9
  * Description:
10
+ * This file is a PHP implementation of rfc2445/rfc5545.
11
  *
12
  * This library is free software; you can redistribute it and/or
13
  * modify it under the terms of the GNU Lesser General Public
45
  */
46
  /*********************************************************************************/
47
  /* version, do NOT remove!! */
48
+ define( 'ICALCREATOR_VERSION', 'iCalcreator 2.16.1' );
49
  /*********************************************************************************/
50
  /*********************************************************************************/
51
  /**
1423
  */
1424
  function selectComponents2( $selectOptions ) {
1425
  $output = array();
1426
+ $allowedComps = array('vevent', 'vtodo', 'vjournal', 'vfreebusy' );
1427
  $allowedProperties = array( 'ATTENDEE', 'CATEGORIES', 'CONTACT', 'LOCATION', 'ORGANIZER', 'PRIORITY', 'RELATED-TO', 'RESOURCES', 'STATUS', 'SUMMARY', 'UID', 'URL' );
1428
  foreach( $this->components as $cix => $component3 ) {
1429
+ if( !in_array( $component3->objName, $allowedComps ))
1430
  continue;
1431
  $uid = $component3->getProperty( 'UID' );
1432
  foreach( $selectOptions as $propName => $pvalue ) {
1540
  * sort iCal compoments
1541
  *
1542
  * ascending sort on properties (if exist) x-current-dtstart, dtstart,
1543
+ * x-current-dtend, dtend, x-current-due, due, duration, created, dtstamp, uid if called without arguments,
1544
  * otherwise sorting on specific (argument) property values
1545
  *
1546
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1582
  continue;
1583
  }
1584
  if( FALSE !== ( $d = $c->getProperty( 'X-CURRENT-DTSTART' ))) {
1585
+ $c->srtk[0] = iCalUtilityFunctions::_strdate2date( $d[1] );
1586
  unset( $c->srtk[0]['unparsedtext'] );
1587
  }
1588
  elseif( FALSE === ( $c->srtk[0] = $c->getProperty( 'dtstart' )))
1589
  $c->srtk[1] = 0; // sortkey 0 : dtstart
1590
  if( FALSE !== ( $d = $c->getProperty( 'X-CURRENT-DTEND' ))) {
1591
+ $c->srtk[1] = iCalUtilityFunctions::_strdate2date( $d[1] ); // sortkey 1 : dtend/due(/dtstart+duration)
1592
  unset( $c->srtk[1]['unparsedtext'] );
1593
  }
1594
  elseif( FALSE === ( $c->srtk[1] = $c->getProperty( 'dtend' ))) {
1595
  if( FALSE !== ( $d = $c->getProperty( 'X-CURRENT-DUE' ))) {
1596
+ $c->srtk[1] = iCalUtilityFunctions::_strdate2date( $d[1] );
1597
  unset( $c->srtk[1]['unparsedtext'] );
1598
  }
1599
  elseif( FALSE === ( $c->srtk[1] = $c->getProperty( 'due' )))
1650
  * parse iCal text/file into vcalendar, components, properties and parameters
1651
  *
1652
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1653
+ * @since 2.15.10 - 2012-10-28
1654
  * @param mixed $unparsedtext, optional, strict rfc2445 formatted, single property string or array of property strings
1655
  * @return bool FALSE if error occurs during parsing
1656
  *
1746
  /* parse data for calendar (this) object */
1747
  if( isset( $this->unparsed ) && is_array( $this->unparsed ) && ( 0 < count( $this->unparsed ))) {
1748
  /* concatenate property values spread over several lines */
 
1749
  $propnames = array( 'calscale','method','prodid','version','x-' );
1750
  $proprows = array();
1751
+ for( $i = 0; $i < count( $this->unparsed ); $i++ ) { // concatenate lines
1752
+ $line = rtrim( $this->unparsed[$i], $nl );
1753
+ while( isset( $this->unparsed[$i+1] ) && !empty( $this->unparsed[$i+1] ) && ( ' ' == $this->unparsed[$i+1]{0} ))
1754
+ $line .= rtrim( substr( $this->unparsed[++$i], 1 ), $nl );
1755
+ $proprows[] = $line;
 
 
 
 
 
 
 
 
 
 
1756
  }
1757
  $paramMStz = array( 'utc-', 'utc+', 'gmt-', 'gmt+' );
1758
  $paramProto3 = array( 'fax:', 'cid:', 'sms:', 'tel:', 'urn:' );
1759
  $paramProto4 = array( 'crid:', 'news:', 'pres:' );
1760
  foreach( $proprows as $line ) {
 
 
1761
  if( '\n' == substr( $line, -2 ))
1762
  $line = substr( $line, 0, -2 );
1763
  /* get property name */
1764
+ $propname = '';
1765
  $cix = 0;
1766
  while( FALSE !== ( $char = substr( $line, $cix, 1 ))) {
1767
  if( in_array( $char, array( ':', ';' )))
1770
  $propname .= $char;
1771
  $cix++;
1772
  }
1773
+ /* skip non standard property names */
1774
+ if(( 'x-' != strtolower( substr( $propname, 0, 2 ))) && !in_array( strtolower( $propname ), $propnames ))
1775
+ continue;
1776
  /* ignore version/prodid properties */
1777
+ if( in_array( strtolower( $propname ), array( 'version', 'prodid' )))
1778
  continue;
1779
+ /* rest of the line is opt.params and value */
1780
  $line = substr( $line, $cix);
1781
  /* separate attributes from value */
1782
  $attr = array();
2506
  if( $this->getConfig( 'allowEmpty' ))
2507
  return $this->_createElement( 'COMPLETED' );
2508
  else return FALSE;
2509
+ $formatted = iCalUtilityFunctions::_date2strdate( $this->completed['value'], 7 );
2510
  $attributes = $this->_createParams( $this->completed['params'] );
2511
  return $this->_createElement( 'COMPLETED', $attributes, $formatted );
2512
  }
2588
  */
2589
  function createCreated() {
2590
  if( empty( $this->created )) return FALSE;
2591
+ $formatted = iCalUtilityFunctions::_date2strdate( $this->created['value'], 7 );
2592
  $attributes = $this->_createParams( $this->created['params'] );
2593
  return $this->_createElement( 'CREATED', $attributes, $formatted );
2594
  }
2662
  * creates formatted output for calendar component property dtend
2663
  *
2664
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2665
+ * @since 2.14.4 - 2012-09-26
2666
  * @return string
2667
  */
2668
  function createDtend() {
2676
  if( $this->getConfig( 'allowEmpty' ))
2677
  return $this->_createElement( 'DTEND' );
2678
  else return FALSE;
2679
+ $parno = ( isset( $this->dtend['params']['VALUE'] ) && ( 'DATE' == $this->dtend['params']['VALUE'] )) ? 3 : null;
2680
+ $formatted = iCalUtilityFunctions::_date2strdate( $this->dtend['value'], $parno );
 
 
 
2681
  $attributes = $this->_createParams( $this->dtend['params'] );
2682
  return $this->_createElement( 'DTEND', $attributes, $formatted );
2683
  }
2727
  !isset( $this->dtstamp['value']['min'] ) &&
2728
  !isset( $this->dtstamp['value']['sec'] ))
2729
  $this->_makeDtstamp();
2730
+ $formatted = iCalUtilityFunctions::_date2strdate( $this->dtstamp['value'], 7 );
2731
  $attributes = $this->_createParams( $this->dtstamp['params'] );
2732
  return $this->_createElement( 'DTSTAMP', $attributes, $formatted );
2733
  }
2735
  * computes datestamp for calendar component object instance dtstamp
2736
  *
2737
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2738
+ * @since 2.14.1 - 2012-09-29
2739
  * @return void
2740
  */
2741
  function _makeDtstamp() {
2742
+ $d = date( 'Y-m-d-H-i-s', mktime( date('H'), date('i'), (date('s') - date( 'Z' )), date('m'), date('d'), date('Y')));
2743
+ $date = explode( '-', $d );
2744
+ $this->dtstamp['value'] = array( 'year' => $date[0], 'month' => $date[1], 'day' => $date[2], 'hour' => $date[3], 'min' => $date[4], 'sec' => $date[5], 'tz' => 'Z' );
 
 
 
 
2745
  $this->dtstamp['params'] = null;
2746
  }
2747
  /**
2773
  * creates formatted output for calendar component property dtstart
2774
  *
2775
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2776
+ * @since 2.14.4 - 2012-09-26
2777
  * @return string
2778
  */
2779
  function createDtstart() {
2790
  }
2791
  if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' )))
2792
  unset( $this->dtstart['value']['tz'], $this->dtstart['params']['TZID'] );
2793
+ $parno = ( isset( $this->dtstart['params']['VALUE'] ) && ( 'DATE' == $this->dtstart['params']['VALUE'] )) ? 3 : null;
2794
+ $formatted = iCalUtilityFunctions::_date2strdate( $this->dtstart['value'], $parno );
 
 
 
2795
  $attributes = $this->_createParams( $this->dtstart['params'] );
2796
  return $this->_createElement( 'DTSTART', $attributes, $formatted );
2797
  }
2830
  * creates formatted output for calendar component property due
2831
  *
2832
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2833
+ * @since 2.14.4 - 2012-09-26
2834
  * @return string
2835
  */
2836
  function createDue() {
2846
  else
2847
  return FALSE;
2848
  }
2849
+ $parno = ( isset( $this->due['params']['VALUE'] ) && ( 'DATE' == $this->due['params']['VALUE'] )) ? 3 : null;
2850
+ $formatted = iCalUtilityFunctions::_date2strdate( $this->due['value'], $parno );
 
 
 
2851
  $attributes = $this->_createParams( $this->due['params'] );
2852
  return $this->_createElement( 'DUE', $attributes, $formatted );
2853
  }
2899
  return $this->_createElement( 'DURATION', array(), null );
2900
  else return FALSE;
2901
  $attributes = $this->_createParams( $this->duration['params'] );
2902
+ return $this->_createElement( 'DURATION', $attributes, iCalUtilityFunctions::_duration2str( $this->duration['value'] ));
2903
  }
2904
  /**
2905
  * set calendar component property duration
2917
  function setDuration( $week, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
2918
  if( empty( $week )) if( $this->getConfig( 'allowEmpty' )) $week = null; else return FALSE;
2919
  if( is_array( $week ) && ( 1 <= count( $week )))
2920
+ $this->duration = array( 'value' => iCalUtilityFunctions::_duration2arr( $week ), 'params' => iCalUtilityFunctions::_setParams( $day ));
2921
  elseif( is_string( $week ) && ( 3 <= strlen( trim( $week )))) {
2922
  $week = trim( $week );
2923
  if( in_array( substr( $week, 0, 1 ), array( '+', '-' )))
2924
  $week = substr( $week, 1 );
2925
+ $this->duration = array( 'value' => iCalUtilityFunctions::_durationStr2arr( $week ), 'params' => iCalUtilityFunctions::_setParams( $day ));
2926
  }
2927
  elseif( empty( $week ) && empty( $day ) && empty( $hour ) && empty( $min ) && empty( $sec ))
2928
  return FALSE;
2929
  else
2930
+ $this->duration = array( 'value' => iCalUtilityFunctions::_duration2arr( array( $week, $day, $hour, $min, $sec )), 'params' => iCalUtilityFunctions::_setParams( $params ));
2931
  return TRUE;
2932
  }
2933
  /*********************************************************************************/
2952
  $content = $attributes = null;
2953
  foreach( $theExdate['value'] as $eix => $exdatePart ) {
2954
  $parno = count( $exdatePart );
2955
+ $formatted = iCalUtilityFunctions::_date2strdate( $exdatePart, $parno );
2956
  if( isset( $theExdate['params']['TZID'] ))
2957
  $formatted = str_replace( 'Z', '', $formatted);
2958
  if( 0 < $eix ) {
2979
  * set calendar component property exdate
2980
  *
2981
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2982
+ * @since 2.14.1 - 2012-10-02
2983
  * @param array exdates
2984
  * @param array $params, optional
2985
  * @param integer $index, optional
3001
  iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default parameter
3002
  foreach( $exdates as $eix => $theExdate ) {
3003
  iCalUtilityFunctions::_strDate2arr( $theExdate );
3004
+ if( iCalUtilityFunctions::_isArrayTimestampDate( $theExdate )) {
3005
+ if( isset( $theExdate['tz'] ) && !iCalUtilityFunctions::_isOffset( $theExdate['tz'] )) {
3006
+ if( isset( $input['params']['TZID'] ))
3007
+ $theExdate['tz'] = $input['params']['TZID'];
3008
+ else
3009
+ $input['params']['TZID'] = $theExdate['tz'];
3010
+ }
3011
  $exdatea = iCalUtilityFunctions::_timestamp2date( $theExdate, $parno );
3012
+ }
3013
+ elseif( is_array( $theExdate )) {
3014
+ $d = iCalUtilityFunctions::_chkDateArr( $theExdate, $parno );
3015
+ if( isset( $d['tz'] ) && ( 'Z' != $d['tz'] ) && iCalUtilityFunctions::_isOffset( $d['tz'] )) {
3016
+ $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $d['tz'] );
3017
+ $exdatea = iCalUtilityFunctions::_strdate2date( $strdate, 7 );
3018
+ unset( $exdatea['unparsedtext'] );
3019
+ }
3020
+ else
3021
+ $exdatea = $d;
3022
+ }
3023
  elseif( 8 <= strlen( trim( $theExdate ))) { // ex. 2006-08-03 10:12:18
3024
+ $exdatea = iCalUtilityFunctions::_strdate2date( $theExdate, $parno );
3025
  unset( $exdatea['unparsedtext'] );
3026
  }
3027
  if( 3 == $parno )
3109
  $fno = 1;
3110
  $cnt = count( $freebusyPart['value']);
3111
  foreach( $freebusyPart['value'] as $periodix => $freebusyPeriod ) {
3112
+ $formatted = iCalUtilityFunctions::_date2strdate( $freebusyPeriod[0] );
3113
  $content .= $formatted;
3114
  $content .= '/';
3115
  $cnt2 = count( $freebusyPeriod[1]);
3121
  isset( $freebusyPeriod[1]['year'] ) &&
3122
  isset( $freebusyPeriod[1]['month'] ) &&
3123
  isset( $freebusyPeriod[1]['day'] )) {
3124
+ $content .= iCalUtilityFunctions::_date2strdate( $freebusyPeriod[1] );
3125
  }
3126
  else { // period= -> dur-time
3127
+ $content .= iCalUtilityFunctions::_duration2str( $freebusyPeriod[1] );
3128
  }
3129
  if( $fno < $cnt )
3130
  $content .= ',';
3167
  $freebusyPairMember = array();
3168
  if( is_array( $fbMember )) {
3169
  if( iCalUtilityFunctions::_isArrayDate( $fbMember )) { // date-time value
3170
+ $freebusyPairMember = iCalUtilityFunctions::_chkDateArr( $fbMember, 7 );
3171
  $freebusyPairMember['tz'] = 'Z';
3172
  }
3173
  elseif( iCalUtilityFunctions::_isArrayTimestampDate( $fbMember )) { // timestamp value
3175
  $freebusyPairMember['tz'] = 'Z';
3176
  }
3177
  else { // array format duration
3178
+ $freebusyPairMember = iCalUtilityFunctions::_duration2arr( $fbMember );
3179
  }
3180
  }
3181
  elseif(( 3 <= strlen( trim( $fbMember ))) && // string format duration
3182
  ( in_array( $fbMember{0}, array( 'P', '+', '-' )))) {
3183
  if( 'P' != $fbMember{0} )
3184
  $fbmember = substr( $fbMember, 1 );
3185
+ $freebusyPairMember = iCalUtilityFunctions::_durationStr2arr( $fbMember );
3186
  }
3187
  elseif( 8 <= strlen( trim( $fbMember ))) { // text date ex. 2006-08-03 10:12:18
3188
+ $freebusyPairMember = iCalUtilityFunctions::_strdate2date( $fbMember, 7 );
3189
  unset( $freebusyPairMember['unparsedtext'] );
3190
  $freebusyPairMember['tz'] = 'Z';
3191
  }
3264
  function createLastModified() {
3265
  if( empty( $this->lastmodified )) return FALSE;
3266
  $attributes = $this->_createParams( $this->lastmodified['params'] );
3267
+ $formatted = iCalUtilityFunctions::_date2strdate( $this->lastmodified['value'], 7 );
3268
  return $this->_createElement( 'LAST-MODIFIED', $attributes, $formatted );
3269
  }
3270
  /**
3438
  * creates formatted output for calendar component property rdate
3439
  *
3440
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3441
+ * @since 2.14.1 - 2012-10-04
3442
  * @return string
3443
  */
3444
  function createRdate() {
3447
  $output = null;
3448
  if( $utctime )
3449
  unset( $this->rdate['params']['TZID'] );
3450
+ foreach( $this->rdate as $rpix => $theRdate ) {
3451
  if( empty( $theRdate['value'] )) {
3452
  if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RDATE' );
3453
  continue;
3458
  $cnt = count( $theRdate['value'] );
3459
  $content = null;
3460
  $rno = 1;
3461
+ foreach( $theRdate['value'] as $rix => $rdatePart ) {
3462
  $contentPart = null;
3463
  if( is_array( $rdatePart ) &&
3464
  isset( $theRdate['params']['VALUE'] ) && ( 'PERIOD' == $theRdate['params']['VALUE'] )) { // PERIOD
3465
  if( $utctime )
3466
  unset( $rdatePart[0]['tz'] );
3467
+ $formatted = iCalUtilityFunctions::_date2strdate( $rdatePart[0] ); // PERIOD part 1
3468
  if( $utctime || !empty( $theRdate['params']['TZID'] ))
3469
  $formatted = str_replace( 'Z', '', $formatted);
 
 
 
 
 
 
 
3470
  $contentPart .= $formatted;
3471
  $contentPart .= '/';
3472
  $cnt2 = count( $rdatePart[1]);
3484
  isset( $rdatePart[1]['day'] )) {
3485
  if( $utctime )
3486
  unset( $rdatePart[1]['tz'] );
3487
+ $formatted = iCalUtilityFunctions::_date2strdate( $rdatePart[1] ); // PERIOD part 2
3488
  if( $utctime || !empty( $theRdate['params']['TZID'] ))
 
 
 
 
 
3489
  $formatted = str_replace( 'Z', '', $formatted );
3490
  $contentPart .= $formatted;
3491
  }
3492
  else { // period= -> dur-time
3493
+ $contentPart .= iCalUtilityFunctions::_duration2str( $rdatePart[1] );
3494
  }
3495
  } // PERIOD end
3496
  else { // SINGLE date start
3497
  if( $utctime )
3498
  unset( $rdatePart['tz'] );
3499
+ $parno = ( isset( $theRdate['params']['VALUE'] ) && ( 'DATE' == isset( $theRdate['params']['VALUE'] ))) ? 3 : null;
3500
+ $formatted = iCalUtilityFunctions::_date2strdate( $rdatePart, $parno );
3501
  if( $utctime || !empty( $theRdate['params']['TZID'] ))
3502
  $formatted = str_replace( 'Z', '', $formatted);
 
 
 
 
 
 
 
 
3503
  $contentPart .= $formatted;
3504
  }
3505
  $content .= $contentPart;
3515
  * set calendar component property rdate
3516
  *
3517
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3518
+ * @since 2.14.1 - 2012-10-04
3519
  * @param array $rdates
3520
  * @param array $params, optional
3521
  * @param integer $index, optional
3560
  foreach( $theRdate as $rix => $rPeriod ) {
3561
  iCalUtilityFunctions::_strDate2arr( $theRdate );
3562
  if( is_array( $rPeriod )) {
3563
+ if( iCalUtilityFunctions::_isArrayTimestampDate( $rPeriod )) { // timestamp
3564
+ if( isset( $rPeriod['tz'] ) && !iCalUtilityFunctions::_isOffset( $rPeriod['tz'] )) {
3565
+ if( isset( $input['params']['TZID'] ))
3566
+ $rPeriod['tz'] = $input['params']['TZID'];
3567
+ else
3568
+ $input['params']['TZID'] = $rPeriod['tz'];
3569
+ }
3570
+ $inputab = iCalUtilityFunctions::_timestamp2date( $rPeriod, $parno );
3571
+ }
3572
+ elseif( iCalUtilityFunctions::_isArrayDate( $rPeriod )) {
3573
+ $d = ( 3 < count ( $rPeriod )) ? iCalUtilityFunctions::_chkDateArr( $rPeriod, $parno ) : iCalUtilityFunctions::_chkDateArr( $rPeriod, 6 );
3574
+ if( isset( $d['tz'] ) && ( 'Z' != $d['tz'] ) && iCalUtilityFunctions::_isOffset( $d['tz'] )) {
3575
+ $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $d['tz'] );
3576
+ $inputab = iCalUtilityFunctions::_strdate2date( $strdate, 7 );
3577
+ unset( $inputab['unparsedtext'] );
3578
+ }
3579
+ else
3580
+ $inputab = $d;
3581
+ }
3582
  elseif (( 1 == count( $rPeriod )) && ( 8 <= strlen( reset( $rPeriod )))) { // text-date
3583
+ $inputab = iCalUtilityFunctions::_strdate2date( reset( $rPeriod ), $parno );
3584
  unset( $inputab['unparsedtext'] );
3585
  }
3586
  else // array format duration
3587
+ $inputab = iCalUtilityFunctions::_duration2arr( $rPeriod );
3588
  }
3589
  elseif(( 3 <= strlen( trim( $rPeriod ))) && // string format duration
3590
  ( in_array( $rPeriod[0], array( 'P', '+', '-' )))) {
3591
  if( 'P' != $rPeriod[0] )
3592
+ $rPeriod = substr( $rPeriod, 1 );
3593
+ $inputab = iCalUtilityFunctions::_durationStr2arr( $rPeriod );
3594
  }
3595
  elseif( 8 <= strlen( trim( $rPeriod ))) { // text date ex. 2006-08-03 10:12:18
3596
+ $inputab = iCalUtilityFunctions::_strdate2date( $rPeriod, $parno );
3597
  unset( $inputab['unparsedtext'] );
3598
  }
3599
+ if(( 0 == $rpix ) && ( 0 == $rix )) {
3600
+ if( isset( $inputab['tz'] ) && in_array( strtoupper( $inputab['tz'] ), $zArr )) {
3601
+ $inputab['tz'] = 'Z';
3602
+ $toZ = TRUE;
3603
+ }
3604
+ }
3605
+ else {
3606
+ if( isset( $inputa[0]['tz'] ) && ( 'Z' == $inputa[0]['tz'] ) && isset( $inputab['year'] ))
3607
+ $inputab['tz'] = 'Z';
3608
+ else
3609
+ unset( $inputab['tz'] );
3610
+ }
3611
+ if( $toZ && isset( $inputab['year'] ) )
3612
+ $inputab['tz'] = 'Z';
3613
+ $inputa[] = $inputab;
3614
  }
3615
  } // PERIOD end
3616
  elseif ( iCalUtilityFunctions::_isArrayTimestampDate( $theRdate )) { // timestamp
3617
+ if( isset( $theRdate['tz'] ) && !iCalUtilityFunctions::_isOffset( $theRdate['tz'] )) {
3618
+ if( isset( $input['params']['TZID'] ))
3619
+ $theRdate['tz'] = $input['params']['TZID'];
3620
+ else
3621
+ $input['params']['TZID'] = $theRdate['tz'];
3622
+ }
3623
  $inputa = iCalUtilityFunctions::_timestamp2date( $theRdate, $parno );
 
 
3624
  }
3625
  else { // date[-time]
3626
+ $inputa = iCalUtilityFunctions::_chkDateArr( $theRdate, $parno );
3627
+ if( isset( $inputa['tz'] ) && ( 'Z' != $inputa['tz'] ) && iCalUtilityFunctions::_isOffset( $inputa['tz'] )) {
3628
+ $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $inputa['year'], $inputa['month'], $inputa['day'], $inputa['hour'], $inputa['min'], $inputa['sec'], $inputa['tz'] );
3629
+ $inputa = iCalUtilityFunctions::_strdate2date( $strdate, 7 );
3630
+ unset( $inputa['unparsedtext'] );
3631
+ }
3632
  }
3633
  }
3634
  elseif( 8 <= strlen( trim( $theRdate ))) { // text date ex. 2006-08-03 10:12:18
3635
+ $inputa = iCalUtilityFunctions::_strdate2date( $theRdate, $parno );
3636
  unset( $inputa['unparsedtext'] );
3637
  if( $toZ )
3638
+ $inputa['tz'] = 'Z';
3639
  }
3640
  if( !isset( $input['params']['VALUE'] ) || ( 'PERIOD' != $input['params']['VALUE'] )) { // no PERIOD
3641
+ if(( 0 == $rpix ) && !$toZ )
3642
+ $toZ = ( isset( $inputa['tz'] ) && in_array( strtoupper( $inputa['tz'] ), $zArr )) ? TRUE : FALSE;
3643
+ if( $toZ )
3644
+ $inputa['tz'] = 'Z';
3645
  if( 3 == $parno )
3646
  unset( $inputa['hour'], $inputa['min'], $inputa['sec'], $inputa['tz'] );
3647
  elseif( isset( $inputa['tz'] ))
3648
+ $inputa['tz'] = (string) $inputa['tz'];
3649
+ if( isset( $input['params']['TZID'] ) || ( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] ))))
 
 
 
3650
  if( !$toZ )
3651
  unset( $inputa['tz'] );
3652
  }
3653
+ $input['value'][] = $inputa;
3654
  }
3655
  if( 3 == $parno ) {
3656
  $input['params']['VALUE'] = 'DATE';
3669
  * creates formatted output for calendar component property recurrence-id
3670
  *
3671
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3672
+ * @since 2.14.4 - 2012-09-26
3673
  * @return string
3674
  */
3675
  function createRecurrenceid() {
3676
  if( empty( $this->recurrenceid )) return FALSE;
3677
  if( empty( $this->recurrenceid['value'] ))
3678
  return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'RECURRENCE-ID' ) : FALSE;
3679
+ $parno = ( isset( $this->recurrenceid['params']['VALUE'] ) && ( 'DATE' == $this->recurrenceid['params']['VALUE'] )) ? 3 : null;
3680
+ $formatted = iCalUtilityFunctions::_date2strdate( $this->recurrenceid['value'], $parno );
 
 
 
3681
  $attributes = $this->_createParams( $this->recurrenceid['params'] );
3682
  return $this->_createElement( 'RECURRENCE-ID', $attributes, $formatted );
3683
  }
4048
  if( isset( $this->trigger['value']['year'] ) &&
4049
  isset( $this->trigger['value']['month'] ) &&
4050
  isset( $this->trigger['value']['day'] ))
4051
+ $content .= iCalUtilityFunctions::_date2strdate( $this->trigger['value'] );
4052
  else {
4053
  if( TRUE !== $this->trigger['value']['relatedStart'] )
4054
  $attributes .= $this->intAttrDelimiter.'RELATED=END';
4055
  if( $this->trigger['value']['before'] )
4056
  $content .= '-';
4057
+ $content .= iCalUtilityFunctions::_duration2str( $this->trigger['value'] );
4058
  }
4059
  $attributes .= $this->_createParams( $this->trigger['params'] );
4060
  return $this->_createElement( 'TRIGGER', $attributes, $content );
4063
  * set calendar component property trigger
4064
  *
4065
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4066
+ * @since 2.14.1 - 2012-09-20
4067
  * @param mixed $year
4068
  * @param mixed $month optional
4069
  * @param int $day optional
4084
  }
4085
  else
4086
  return FALSE;
4087
+ if( iCalUtilityFunctions::_isArrayTimestampDate( $year )) { // timestamp UTC
4088
  $params = iCalUtilityFunctions::_setParams( $month );
4089
  $date = iCalUtilityFunctions::_timestamp2date( $year, 7 );
4090
  foreach( $date as $k => $v )
4117
  $before = ( '-' == $year[0] ) ? TRUE : FALSE;
4118
  if( 'P' != $year[0] )
4119
  $year = substr( $year, 1 );
4120
+ $date = iCalUtilityFunctions::_durationStr2arr( $year);
4121
  }
4122
  else // date
4123
+ $date = iCalUtilityFunctions::_strdate2date( $year, 7 );
4124
  unset( $year, $month, $day, $date['unparsedtext'] );
4125
  if( empty( $date ))
4126
  $sec = 0;
4724
  * creates formatted output for calendar component property data value type recur
4725
  *
4726
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4727
+ * @since 2.14.1 - 2012-10-06
4728
  * @param array $recurlabel
4729
  * @param array $recurdata
4730
  * @return string
4745
  break;
4746
  }
4747
  case 'UNTIL': {
4748
+ $parno = ( isset( $rulevalue['hour'] )) ? 7 : 3;
4749
+ $content2 .= ';UNTIL='.iCalUtilityFunctions::_date2strdate( $rulevalue, $parno );
4750
  break;
4751
  }
4752
  case 'COUNT':
4887
  case 'PROPINFO':
4888
  $output = array();
4889
  if( !in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) {
4890
+ if( empty( $this->uid['value'] )) $this->_makeuid();
4891
  $output['UID'] = 1;
4892
+ if( empty( $this->dtstamp )) $this->_makeDtstamp();
4893
+ $output['DTSTAMP'] = 1;
4894
  }
 
4895
  if( !empty( $this->summary )) $output['SUMMARY'] = 1;
4896
  if( !empty( $this->description )) $output['DESCRIPTION'] = count( $this->description );
4897
  if( !empty( $this->dtstart )) $output['DTSTART'] = 1;
4937
  if( !empty( $this->xprop )) $output['X-PROP'] = count( $this->xprop );
4938
  return $output;
4939
  break;
4940
+ case 'SETPROPERTYNAMES':
4941
+ return array_keys( $this->getConfig( 'propinfo' ));
4942
+ break;
4943
  case 'TZID':
4944
  return $this->dtzid;
4945
  break;
5776
  * parse component unparsed data into properties
5777
  *
5778
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
5779
+ * @since 2.15.10 - 2012-10-28
5780
  * @param mixed $unparsedtext, optional, strict rfc2445 formatted, single property string or array of strings
5781
  * @return bool FALSE if error occurs during parsing
5782
  *
5783
  */
5784
  function parse( $unparsedtext=null ) {
5785
+ $nl = $this->getConfig( 'nl' );
5786
  if( !empty( $unparsedtext )) {
 
5787
  if( is_array( $unparsedtext ))
5788
  $unparsedtext = implode( '\n'.$nl, $unparsedtext );
5789
  $unparsedtext = explode( $nl, iCalUtilityFunctions::convEolChar( $unparsedtext, $nl ));
5858
  , 'summary', 'transp', 'trigger', 'tzid', 'tzname', 'tzoffsetfrom'
5859
  , 'tzoffsetto', 'tzurl', 'uid', 'url', 'x-' );
5860
  $proprows = array();
5861
+ for( $i = 0; $i < count( $this->unparsed ); $i++ ) { // concatenate lines
5862
+ $line = rtrim( $this->unparsed[$i], $nl );
5863
+ while( isset( $this->unparsed[$i+1] ) && !empty( $this->unparsed[$i+1] ) && ( ' ' == $this->unparsed[$i+1]{0} ))
5864
+ $line .= rtrim( substr( $this->unparsed[++$i], 1 ), $nl );
5865
+ $proprows[] = $line;
 
 
 
 
 
 
 
 
 
 
5866
  }
5867
  /* parse each property 'line' */
5868
  $paramMStz = array( 'utc-', 'utc+', 'gmt-', 'gmt+' );
5869
  $paramProto3 = array( 'fax:', 'cid:', 'sms:', 'tel:', 'urn:' );
5870
  $paramProto4 = array( 'crid:', 'news:', 'pres:' );
5871
  foreach( $proprows as $line ) {
 
 
5872
  if( '\n' == substr( $line, -2 ))
5873
  $line = substr( $line, 0, -2 );
5874
+ /* get propname */
5875
  $propname = null;
5876
  $cix = 0;
5877
  while( isset( $line[$cix] )) {
5885
  $propname2 = $propname;
5886
  $propname = 'X-';
5887
  }
5888
+ if( !in_array( strtolower( $propname ), $propnames )) // skip non standard property names
5889
+ continue;
5890
  /* rest of the line is opt.params and value */
5891
  $line = substr( $line, $cix );
5892
  /* separate attributes from value */
6118
  * return a copy of this component
6119
  *
6120
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
6121
+ * @since 2.15.4 - 2012-10-18
6122
  * @return object
6123
  */
6124
  function copy() {
6125
+ return unserialize( serialize( $this ));
 
 
6126
  }
6127
  /*********************************************************************************/
6128
  /*********************************************************************************/
7217
  return self::$m_pInstance;
7218
  }
7219
  /**
7220
+ * ensures internal date-time/date format (keyed array) for an input date-time/date array (keyed or unkeyed)
7221
+ *
7222
+ * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7223
+ * @since 2.14.1 - 2012-09-27
7224
+ * @param array $datetime
7225
+ * @param int $parno optional, default FALSE
7226
+ * @return array
7227
+ */
7228
+ public static function _date_time_array( $datetime, $parno=FALSE ) {
7229
+ return iCalUtilityFunctions::_chkDateArr( $datetime, $parno );
7230
+ }
7231
+ public static function _chkDateArr( $datetime, $parno=FALSE ) {
7232
+ $output = array();
7233
+ foreach( $datetime as $dateKey => $datePart ) {
7234
+ switch ( $dateKey ) {
7235
+ case '0': case 'year': $output['year'] = $datePart; break;
7236
+ case '1': case 'month': $output['month'] = $datePart; break;
7237
+ case '2': case 'day': $output['day'] = $datePart; break;
7238
+ }
7239
+ if( 3 != $parno ) {
7240
+ switch ( $dateKey ) {
7241
+ case '0':
7242
+ case '1':
7243
+ case '2': break;
7244
+ case '3': case 'hour': $output['hour'] = $datePart; break;
7245
+ case '4': case 'min' : $output['min'] = $datePart; break;
7246
+ case '5': case 'sec' : $output['sec'] = $datePart; break;
7247
+ case '6': case 'tz' : $output['tz'] = $datePart; break;
7248
+ }
7249
+ }
7250
+ }
7251
+ if( 3 != $parno ) {
7252
+ if( !isset( $output['hour'] )) $output['hour'] = 0;
7253
+ if( !isset( $output['min'] )) $output['min'] = 0;
7254
+ if( !isset( $output['sec'] )) $output['sec'] = 0;
7255
+ if( isset( $output['tz'] ) &&
7256
+ (( '+0000' == $output['tz'] ) || ( '-0000' == $output['tz'] ) || ( '+000000' == $output['tz'] ) || ( '-000000' == $output['tz'] )))
7257
+ $output['tz'] = 'Z';
7258
+ }
7259
+ return $output;
7260
+ }
7261
+ /**
7262
+ * check date(-time) and params arrays for an opt. timezone and if it is a DATE-TIME or DATE (updates $parno and params)
7263
  *
7264
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7265
  * @since 2.10.30 - 2012-01-16
7266
  * @param array $date, date to check
7267
  * @param int $parno, no of date parts (i.e. year, month.. .)
7268
+ * @param array $params, property parameters
7269
+ * @return void
7270
  */
7271
  public static function _chkdatecfg( $theDate, & $parno, & $params ) {
7272
  if( isset( $params['TZID'] ))
7299
  elseif((( 8 == strlen( $date ) && ctype_digit( $date )) || ( 11 >= strlen( $date ))) &&
7300
  ( !isset( $params['VALUE'] ) || !in_array( $params['VALUE'], array( 'DATE-TIME', 'PERIOD' ))))
7301
  $parno = 3; // DATE
7302
+ $date = iCalUtilityFunctions::_strdate2date( $date, $parno );
7303
  unset( $date['unparsedtext'] );
7304
  if( !empty( $date['tz'] )) {
7305
  $parno = 7;
7316
  /**
7317
  * byte oriented line folding fix
7318
  *
7319
+ * remove any line-endings that may include spaces or tabs
7320
+ * and convert all line endings (iCal default '\r\n'),
7321
  * takes care of '\r\n', '\r' and '\n' and mixed '\r\n'+'\r', '\r\n'+'\n'
7322
  *
7323
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7349
  return $outp;
7350
  }
7351
  /**
7352
+ * create a calendar timezone and standard/daylight components
7353
  *
7354
  * Result when 'Europe/Stockholm' and no from/to arguments is used as timezone:
7355
  *
7370
  * END:VTIMEZONE
7371
  *
7372
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7373
+ * @since 2.16.1 - 2012-11-26
7374
  * Generates components for all transitions in a date range, based on contribution by Yitzchok Lavi <icalcreator@onebigsystem.com>
7375
  * Additional changes jpirkey
7376
  * @param object $calendar, reference to an iCalcreator calendar instance
7377
  * @param string $timezone, a PHP5 (DateTimeZone) valid timezone
7378
  * @param array $xProp, *[x-propName => x-propValue], optional
7379
+ * @param int $from a unix timestamp
7380
+ * @param int $to a unix timestamp
7381
  * @return bool
7382
  */
7383
  public static function createTimezone( & $calendar, $timezone, $xProp=array(), $from=null, $to=null ) {
 
 
7384
  if( empty( $timezone ))
7385
  return FALSE;
7386
+ if( !empty( $from ) && !is_int( $from ))
7387
+ return FALSE;
7388
+ if( !empty( $to ) && !is_int( $to ))
7389
+ return FALSE;
7390
  try {
7391
  $dtz = new DateTimeZone( $timezone );
7392
  $transitions = $dtz->getTransitions();
 
7393
  $utcTz = new DateTimeZone( 'UTC' );
7394
  }
7395
+ catch( Exception $e ) { return FALSE; }
7396
+ if( empty( $to )) {
 
 
7397
  $dates = array_keys( $calendar->getProperty( 'dtstart' ));
7398
+ if( empty( $dates ))
7399
+ $dates = array( date( 'Ymd' ));
7400
+ }
7401
  if( !empty( $from ))
7402
+ $dateFrom = new DateTime( "@$from" ); // set lowest date (UTC)
7403
  else {
7404
+ $from = reset( $dates ); // set lowest date to the lowest dtstart date
7405
+ $dateFrom = new DateTime( $from.'T000000', $dtz );
7406
  $dateFrom->modify( '-1 month' ); // set $dateFrom to one month before the lowest date
7407
+ $dateFrom->setTimezone( $utcTz ); // convert local date to UTC
7408
  }
7409
+ $dateFromYmd = $dateFrom->format('Y-m-d' );
7410
  if( !empty( $to ))
7411
+ $dateTo = new DateTime( "@$to" ); // set end date (UTC)
7412
  else {
7413
+ $to = end( $dates ); // set highest date to the highest dtstart date
7414
+ $dateTo = new DateTime( $to.'T235959', $dtz );
 
 
7415
  $dateTo->modify( '+1 year' ); // set $dateTo to one year after the highest date
7416
+ $dateTo->setTimezone( $utcTz ); // convert local date to UTC
7417
  }
7418
+ $dateToYmd = $dateTo->format('Y-m-d' );
7419
+ unset( $dtz );
7420
  $transTemp = array();
7421
+ $prevOffsetfrom = 0;
7422
  $stdIx = $dlghtIx = null;
 
7423
  $prevTrans = FALSE;
7424
  foreach( $transitions as $tix => $trans ) { // all transitions in date-time order!!
7425
+ $date = new DateTime( "@{$trans['ts']}" ); // set transition date (UTC)
7426
+ $transDateYmd = $date->format('Y-m-d' );
7427
+ if ( $transDateYmd < $dateFromYmd ) {
7428
  $prevOffsetfrom = $trans['offset']; // previous trans offset will be 'next' trans offsetFrom
7429
  $prevTrans = $trans; // save it in case we don't find any that match
7430
  $prevTrans['offsetfrom'] = ( 0 < $tix ) ? $transitions[$tix-1]['offset'] : 0;
7431
  continue;
7432
  }
7433
+ if( $transDateYmd > $dateToYmd )
7434
  break; // loop always (?) breaks here
7435
  if( !empty( $prevOffsetfrom ) || ( 0 == $prevOffsetfrom )) {
7436
  $trans['offsetfrom'] = $prevOffsetfrom; // i.e. set previous offsetto as offsetFrom
7437
  $date->modify( $trans['offsetfrom'].'seconds' ); // convert utc date to local date
7438
+ $d = $date->format( 'Y-n-j-G-i-s' ); // set date to array to ease up dtstart and (opt) rdate setting
7439
+ $d = explode( '-', $d );
7440
+ $trans['time'] = array( 'year' => $d[0], 'month' => $d[1], 'day' => $d[2], 'hour' => $d[3], 'min' => $d[4], 'sec' => $d[5] );
 
 
 
7441
  }
7442
  $prevOffsetfrom = $trans['offset'];
 
7443
  if( TRUE !== $trans['isdst'] ) { // standard timezone
7444
+ if( !empty( $stdIx ) && isset( $transTemp[$stdIx]['offsetfrom'] ) && // check for any repeating rdate's (in order)
7445
+ ( $transTemp[$stdIx]['abbr'] == $trans['abbr'] ) &&
7446
+ ( $transTemp[$stdIx]['offsetfrom'] == $trans['offsetfrom'] ) &&
7447
+ ( $transTemp[$stdIx]['offset'] == $trans['offset'] )) {
7448
+ $transTemp[$stdIx]['rdate'][] = $trans['time'];
 
 
7449
  continue;
7450
  }
7451
  $stdIx = $tix;
 
7452
  } // end standard timezone
7453
  else { // daylight timezone
7454
+ if( !empty( $dlghtIx ) && isset( $transTemp[$dlghtIx]['offsetfrom'] ) && // check for any repeating rdate's (in order)
7455
+ ( $transTemp[$dlghtIx]['abbr'] == $trans['abbr'] ) &&
7456
+ ( $transTemp[$dlghtIx]['offsetfrom'] == $trans['offsetfrom'] ) &&
7457
+ ( $transTemp[$dlghtIx]['offset'] == $trans['offset'] )) {
7458
+ $transTemp[$dlghtIx]['rdate'][] = $trans['time'];
 
 
7459
  continue;
7460
  }
7461
  $dlghtIx = $tix;
 
7462
  } // end daylight timezone
 
 
 
 
 
 
 
7463
  $transTemp[$tix] = $trans;
7464
  } // end foreach( $transitions as $tix => $trans )
7465
  $tz = & $calendar->newComponent( 'vtimezone' );
7471
  }
7472
  if( empty( $transTemp )) { // if no match found
7473
  if( $prevTrans ) { // then we use the last transition (before startdate) for the tz info
7474
+ $date = new DateTime( "@{$prevTrans['ts']}" ); // set transition date (UTC)
7475
  $date->modify( $prevTrans['offsetfrom'].'seconds' ); // convert utc date to local date
7476
+ $d = $date->format( 'Y-n-j-G-i-s' ); // set date to array to ease up dtstart setting
7477
+ $d = explode( '-', $d );
7478
+ $prevTrans['time'] = array( 'year' => $d[0], 'month' => $d[1], 'day' => $d[2], 'hour' => $d[3], 'min' => $d[4], 'sec' => $d[5] );
 
 
 
7479
  $transTemp[0] = $prevTrans;
7480
  }
7481
  else { // or we use the timezone identifier to BUILD the standard tz info (?)
7482
+ $date = new DateTime( 'now', new DateTimeZone( $timezone ));
7483
+ $transTemp[0] = array( 'time' => $date->format( 'Y-m-d\TH:i:s O' )
7484
  , 'offset' => $date->format( 'Z' )
7485
  , 'offsetfrom' => $date->format( 'Z' )
7486
+ , 'isdst' => FALSE );
7487
  }
7488
  }
7489
  unset( $transitions, $date, $prevTrans );
7490
+ foreach( $transTemp as $tix => $trans ) {
7491
  $type = ( TRUE !== $trans['isdst'] ) ? 'standard' : 'daylight';
7492
  $scomp = & $tz->newComponent( $type );
7493
  $scomp->setProperty( 'dtstart', $trans['time'] );
7494
+ // $scomp->setProperty( 'x-utc-timestamp', $tix.' : '.$trans['ts'] ); // test ###
7495
  if( !empty( $trans['abbr'] ))
7496
  $scomp->setProperty( 'tzname', $trans['abbr'] );
7497
  if( isset( $trans['offsetfrom'] ))
7503
  return TRUE;
7504
  }
7505
  /**
7506
+ * creates formatted output for calendar component property data value type date/date-time
7507
  *
7508
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7509
+ * @since 2.14.1 - 2012-09-17
7510
+ * @param array $datetime
7511
+ * @param int $parno, optional, default 6
7512
+ * @return string
7513
  */
7514
+ public static function _format_date_time( $datetime, $parno=6 ) {
7515
+ return iCalUtilityFunctions::_date2strdate( $datetime, $parno );
 
 
 
 
 
 
 
 
 
 
 
 
7516
  }
7517
+ public static function _date2strdate( $datetime, $parno=6 ) {
7518
+ if( !isset( $datetime['year'] ) &&
7519
+ !isset( $datetime['month'] ) &&
7520
+ !isset( $datetime['day'] ) &&
7521
+ !isset( $datetime['hour'] ) &&
7522
+ !isset( $datetime['min'] ) &&
7523
+ !isset( $datetime['sec'] ))
7524
+ return;
7525
+ $output = null;
7526
+ foreach( $datetime as $dkey => & $dvalue )
7527
+ if( 'tz' != $dkey ) $dvalue = (integer) $dvalue;
7528
+ $output = sprintf( '%04d%02d%02d', $datetime['year'], $datetime['month'], $datetime['day'] );
7529
+ if( 3 == $parno )
7530
+ return $output;
7531
+ if( !isset( $datetime['hour'] )) $datetime['hour'] = 0;
7532
+ if( !isset( $datetime['min'] )) $datetime['min'] = 0;
7533
+ if( !isset( $datetime['sec'] )) $datetime['sec'] = 0;
7534
+ $output .= sprintf( 'T%02d%02d%02d', $datetime['hour'], $datetime['min'], $datetime['sec'] );
7535
+ if( isset( $datetime['tz'] ) && ( '' < trim( $datetime['tz'] ))) {
7536
+ $datetime['tz'] = trim( $datetime['tz'] );
7537
+ if( 'Z' == $datetime['tz'] )
7538
+ $parno = 7;
7539
+ elseif( iCalUtilityFunctions::_isOffset( $datetime['tz'] )) {
7540
+ $parno = 7;
7541
+ $offset = iCalUtilityFunctions::_tz2offset( $datetime['tz'] );
7542
+ try {
7543
+ $d = new DateTime( $output, new DateTimeZone( 'UTC' ));
7544
+ if( 0 != $offset ) // adjust för offset
7545
+ $d->modify( "$offset seconds" );
7546
+ $output = $d->format( 'Ymd\THis' );
7547
+ }
7548
+ catch( Exception $e ) {
7549
+ $output = date( 'Ymd\THis', mktime( $datetime['hour'], $datetime['min'], ($datetime['sec'] - $offset), $datetime['month'], $datetime['day'], $datetime['year'] ));
7550
  }
7551
  }
7552
+ if( 7 == $parno )
7553
+ $output .= 'Z';
 
 
 
 
 
 
 
 
 
7554
  }
7555
  return $output;
7556
  }
7557
  /**
7558
+ * convert a date/datetime (array) to timestamp
7559
  *
7560
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7561
+ * @since 2.14.1 - 2012-09-29
7562
+ * @param array $datetime datetime(/date)
7563
+ * @param string $wtz timezone
7564
+ * @return int
 
7565
  */
7566
+ public static function _date2timestamp( $datetime, $wtz=null ) {
7567
+ if( !isset( $datetime['hour'] )) $datetime['hour'] = 0;
7568
+ if( !isset( $datetime['min'] )) $datetime['min'] = 0;
7569
+ if( !isset( $datetime['sec'] )) $datetime['sec'] = 0;
7570
+ if( empty( $wtz ) && ( !isset( $datetime['tz'] ) || empty( $datetime['tz'] )))
7571
+ return mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year'] );
7572
+ $output = $offset = 0;
7573
+ if( empty( $wtz )) {
7574
+ if( iCalUtilityFunctions::_isOffset( $datetime['tz'] )) {
7575
+ $offset = iCalUtilityFunctions::_tz2offset( $datetime['tz'] ) * -1;
7576
+ $wtz = 'UTC';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7577
  }
7578
+ else
7579
+ $wtz = $datetime['tz'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7580
  }
7581
+ if(( 'Z' == $wtz ) || ( 'GMT' == strtoupper( $wtz )))
7582
+ $wtz = 'UTC';
7583
+ try {
7584
+ $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', $datetime['year'], $datetime['month'], $datetime['day'], $datetime['hour'], $datetime['min'], $datetime['sec'] );
7585
+ $d = new DateTime( $strdate, new DateTimeZone( $wtz ));
7586
+ if( 0 != $offset ) // adjust for offset
7587
+ $d->modify( $offset.' seconds' );
7588
+ $output = $d->format( 'U' );
7589
+ unset( $d );
7590
+ }
7591
+ catch( Exception $e ) {
7592
+ $output = mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year'] );
7593
  }
 
 
7594
  return $output;
7595
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7596
  /**
7597
  * ensures internal duration format for input in array format
7598
  *
7599
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7600
+ * @since 2.14.1 - 2012-09-25
7601
  * @param array $duration
7602
  * @return array
7603
  */
7604
  public static function _duration_array( $duration ) {
7605
+ return iCalUtilityFunctions::_duration2arr( $duration );
7606
+ }
7607
+ public static function _duration2arr( $duration ) {
7608
  $output = array();
7609
  if( is_array( $duration ) &&
7610
  ( 1 == count( $duration )) &&
7611
  isset( $duration['sec'] ) &&
7612
  ( 60 < $duration['sec'] )) {
7613
  $durseconds = $duration['sec'];
7614
+ $output['week'] = (int) floor( $durseconds / ( 60 * 60 * 24 * 7 ));
7615
+ $durseconds = $durseconds % ( 60 * 60 * 24 * 7 );
7616
+ $output['day'] = (int) floor( $durseconds / ( 60 * 60 * 24 ));
7617
+ $durseconds = $durseconds % ( 60 * 60 * 24 );
7618
+ $output['hour'] = (int) floor( $durseconds / ( 60 * 60 ));
7619
+ $durseconds = $durseconds % ( 60 * 60 );
7620
+ $output['min'] = (int) floor( $durseconds / ( 60 ));
7621
+ $output['sec'] = ( $durseconds % ( 60 ));
7622
  }
7623
  else {
7624
  foreach( $duration as $durKey => $durValue ) {
7649
  return $output;
7650
  }
7651
  /**
7652
+ * convert startdate+duration to a array format datetime
7653
  *
7654
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7655
+ * @since 2.15.12 - 2012-10-31
7656
+ * @param array $startdate
7657
+ * @param array $duration
7658
+ * @return array, date format
7659
+ */
7660
+ public static function _duration2date( $startdate, $duration ) {
7661
+ $dateOnly = ( isset( $startdate['hour'] ) || isset( $startdate['min'] ) || isset( $startdate['sec'] )) ? FALSE : TRUE;
7662
+ $startdate['hour'] = ( isset( $startdate['hour'] )) ? $startdate['hour'] : 0;
7663
+ $startdate['min'] = ( isset( $startdate['min'] )) ? $startdate['min'] : 0;
7664
+ $startdate['sec'] = ( isset( $startdate['sec'] )) ? $startdate['sec'] : 0;
7665
+ $dtend = 0;
7666
+ if( isset( $duration['week'] )) $dtend += ( $duration['week'] * 7 * 24 * 60 * 60 );
7667
+ if( isset( $duration['day'] )) $dtend += ( $duration['day'] * 24 * 60 * 60 );
7668
+ if( isset( $duration['hour'] )) $dtend += ( $duration['hour'] * 60 *60 );
7669
+ if( isset( $duration['min'] )) $dtend += ( $duration['min'] * 60 );
7670
+ if( isset( $duration['sec'] )) $dtend += $duration['sec'];
7671
+ $date = date( 'Y-m-d-H-i-s', mktime((int) $startdate['hour'], (int) $startdate['min'], (int) ( $startdate['sec'] + $dtend ), (int) $startdate['month'], (int) $startdate['day'], (int) $startdate['year'] ));
7672
+ $d = explode( '-', $date );
7673
+ $dtend2 = array( 'year' => $d[0], 'month' => $d[1], 'day' => $d[2], 'hour' => $d[3], 'min' => $d[4], 'sec' => $d[5] );
7674
+ if( isset( $startdate['tz'] ))
7675
+ $dtend2['tz'] = $startdate['tz'];
7676
+ if( $dateOnly && (( 0 == $dtend2['hour'] ) && ( 0 == $dtend2['min'] ) && ( 0 == $dtend2['sec'] )))
7677
+ unset( $dtend2['hour'], $dtend2['min'], $dtend2['sec'] );
7678
+ return $dtend2;
7679
+ }
7680
+ /**
7681
+ * ensures internal duration format for an input string (iCal) formatted duration
7682
+ *
7683
+ * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7684
+ * @since 2.14.1 - 2012-09-25
7685
  * @param string $duration
7686
  * @return array
7687
  */
7688
  public static function _duration_string( $duration ) {
7689
+ return iCalUtilityFunctions::_durationStr2arr( $duration );
7690
+ }
7691
+ public static function _durationStr2arr( $duration ) {
7692
  $duration = (string) trim( $duration );
7693
  while( 'P' != strtoupper( substr( $duration, 0, 1 ))) {
7694
  if( 0 < strlen( $duration ))
7730
  $val .= substr( $duration, $ix, 1 );
7731
  }
7732
  }
7733
+ return iCalUtilityFunctions::_duration2arr( $output );
7734
  }
7735
  /**
7736
+ * creates formatted output for calendar component property data value type duration
7737
  *
7738
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7739
+ * @since 2.15.8 - 2012-10-30
7740
+ * @param array $duration, array( week, day, hour, min, sec )
7741
+ * @return string
 
7742
  */
7743
+ public static function _format_duration( $duration ) {
7744
+ return iCalUtilityFunctions::_duration2str( $duration );
7745
+ }
7746
+ public static function _duration2str( $duration ) {
7747
+ if( isset( $duration['week'] ) ||
7748
+ isset( $duration['day'] ) ||
7749
+ isset( $duration['hour'] ) ||
7750
+ isset( $duration['min'] ) ||
7751
+ isset( $duration['sec'] ))
7752
+ $ok = TRUE;
7753
+ else
7754
+ return;
7755
+ if( isset( $duration['week'] ) && ( 0 < $duration['week'] ))
7756
+ return 'P'.$duration['week'].'W';
7757
+ $output = 'P';
7758
+ if( isset($duration['day'] ) && ( 0 < $duration['day'] ))
7759
+ $output .= $duration['day'].'D';
7760
+ if(( isset( $duration['hour']) && ( 0 < $duration['hour'] )) ||
7761
+ ( isset( $duration['min']) && ( 0 < $duration['min'] )) ||
7762
+ ( isset( $duration['sec']) && ( 0 < $duration['sec'] ))) {
7763
+ $output .= 'T';
7764
+ $output .= ( isset( $duration['hour']) && ( 0 < $duration['hour'] )) ? $duration['hour'].'H' : '0H';
7765
+ $output .= ( isset( $duration['min']) && ( 0 < $duration['min'] )) ? $duration['min']. 'M' : '0M';
7766
+ $output .= ( isset( $duration['sec']) && ( 0 < $duration['sec'] )) ? $duration['sec']. 'S' : '0S';
7767
+ }
7768
+ if( 'P' == $output )
7769
+ $output = 'PT0H0M0S';
7770
+ return $output;
 
 
 
7771
  }
7772
  /**
7773
+ * removes expkey+expvalue from array and returns hitval (if found) else returns elseval
7774
  *
7775
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7776
  * @since 2.4.16 - 2008-11-08
7798
  return $elseVal;
7799
  }
7800
  /**
7801
+ * checks if input contains a (array formatted) date/time
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7802
  *
7803
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7804
  * @since 2.11.8 - 2012-01-20
7823
  if(( isset( $input[0] ) && isset( $input[1] ) && isset( $input[2] )) &&
7824
  checkdate( (int) $input[1], (int) $input[2], (int) $input[0] ))
7825
  return TRUE;
7826
+ $input = iCalUtilityFunctions::_strdate2date( $input[1].'/'.$input[2].'/'.$input[0], 3 ); // m - d - Y
7827
  if( isset( $input['year'] ) && isset( $input['month'] ) && isset( $input['day'] ))
7828
  return checkdate( (int) $input['month'], (int) $input['day'], (int) $input['year'] );
7829
  return FALSE;
7840
  return ( is_array( $input ) && isset( $input['timestamp'] )) ? TRUE : FALSE ;
7841
  }
7842
  /**
7843
+ * controls if input string contains (trailing) UTC/iCal offset
7844
  *
7845
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7846
+ * @since 2.14.1 - 2012-09-21
7847
  * @param string $input
7848
  * @return bool
7849
  */
7853
  return TRUE;
7854
  elseif(( 5 <= strlen( $input )) &&
7855
  ( in_array( substr( $input, -5, 1 ), array( '+', '-' ))) &&
7856
+ ( '0000' <= substr( $input, -4 )) && ( '9999' >= substr( $input, -4 )))
7857
  return TRUE;
7858
  elseif(( 7 <= strlen( $input )) &&
7859
  ( in_array( substr( $input, -7, 1 ), array( '+', '-' ))) &&
7860
+ ( '000000' <= substr( $input, -6 )) && ( '999999' >= substr( $input, -6 )))
7861
  return TRUE;
7862
  return FALSE;
7863
  }
7866
  * matching (MS) UCT offset and time zone descriptors
7867
  *
7868
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7869
+ * @since 2.14.1 - 2012-09-16
7870
  * @param string $timezone, input/output variable reference
7871
  * @return bool
7872
  */
7873
  public static function ms2phpTZ( & $timezone ) {
 
 
7874
  if( empty( $timezone ))
7875
  return FALSE;
7876
  $search = str_replace( '"', '', $timezone );
7931
  return FALSE;
7932
  }
7933
  /**
7934
+ * transforms offset in seconds to [-/+]hhmm[ss]
7935
  *
7936
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7937
  * @since 2011-05-02
7968
  return $prefix.$output;
7969
  }
7970
  /**
7971
+ * updates an array with dates based on a recur pattern
7972
  *
7973
  * if missing, UNTIL is set 1 year from startdate (emergency break)
7974
+ *
7975
+ * Some additional data from the author
7976
+ * The $result array is an array([timestamp] => TRUE).
7977
+ *
7978
+ * The $startdate and $enddate arguments describes the period start and end
7979
+ * dates where recurrences may appear.
7980
+ *
7981
+ * The $wdate arg. is the component start date (DTSTART), lower than end date.
7982
+ *
7983
+ * The format of the input $wdate, $startdate and $enddate args. are the
7984
+ * iCalcreator internal date format (array( 'year' =>.., 'month' =>.. 'day'
7985
+ * => .., 'hour' => .., 'min'=> .., 'sec' => .. )).
7986
+ * The function do not do any timezone convertions, I don't think it matters
7987
+ * here, only managing YMD dates.
7988
+ *
7989
+ * You can find a brief overview of the $recur array at
7990
+ * kigkonsult.se/iCalcreator/docs/using.html#EXRULE,
7991
+ * also output of calendarComponent::getProperty( "RRULE" ).
7992
  *
7993
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
7994
  * @since 2.10.19 - 2011-10-31
7997
  * @param array $wdate, component start date
7998
  * @param array $startdate, start date
7999
  * @param array $enddate, optional
8000
+ * @return void
8001
  * @todo BYHOUR, BYMINUTE, BYSECOND, WEEKLY at year end/start
8002
  */
8003
  public static function _recur2date( & $result, $recur, $wdate, $startdate, $enddate=FALSE ) {
8395
  * convert input format for exrule and rrule to internal format
8396
  *
8397
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8398
+ * @since 2.14.1 - 2012-09-24
8399
  * @param array $rexrule
8400
  * @return array
8401
  */
8409
  $input[$rexrulelabel] = $rexrulevalue;
8410
  else {
8411
  iCalUtilityFunctions::_strDate2arr( $rexrulevalue );
8412
+ if( iCalUtilityFunctions::_isArrayTimestampDate( $rexrulevalue )) // timestamp, always date-time UTC
8413
+ $input[$rexrulelabel] = iCalUtilityFunctions::_timestamp2date( $rexrulevalue, 7, 'UTC' );
8414
+ elseif( iCalUtilityFunctions::_isArrayDate( $rexrulevalue )) { // date or UTC date-time
8415
+ $parno = ( isset( $rexrulevalue['hour'] ) || isset( $rexrulevalue[4] )) ? 7 : 3;
8416
+ $d = iCalUtilityFunctions::_chkDateArr( $rexrulevalue, $parno );
8417
+ if(( 3 < $parno ) && isset( $d['tz'] ) && ( 'Z' != $d['tz'] ) && iCalUtilityFunctions::_isOffset( $d['tz'] )) {
8418
+ $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $d['tz'] );
8419
+ $input[$rexrulelabel] = iCalUtilityFunctions::_strdate2date( $strdate, 7 );
8420
+ unset( $input[$rexrulelabel]['unparsedtext'] );
8421
+ }
8422
+ else
8423
+ $input[$rexrulelabel] = $d;
8424
+ }
8425
+ elseif( 8 <= strlen( trim( $rexrulevalue ))) { // ex. textual date-time 2006-08-03 10:12:18 => UTC
8426
+ $input[$rexrulelabel] = iCalUtilityFunctions::_strdate2date( $rexrulevalue );
8427
  unset( $input['$rexrulelabel']['unparsedtext'] );
8428
  }
8429
  if(( 3 < count( $input[$rexrulelabel] )) && !isset( $input[$rexrulelabel]['tz'] ))
8485
  * convert format for input date to internal date with parameters
8486
  *
8487
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8488
+ * @since 2.14.1 - 2012-10-15
8489
+ * @param mixed $year
8490
+ * @param mixed $month optional
8491
+ * @param int $day optional
8492
+ * @param int $hour optional
8493
+ * @param int $min optional
8494
+ * @param int $sec optional
8495
+ * @param string $tz optional
8496
+ * @param array $params optional
8497
+ * @param string $caller optional
8498
  * @param string $objName optional
8499
+ * @param string $tzid optional
8500
  * @return array
8501
  */
8502
  public static function _setDate( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE, $caller=null, $objName=null, $tzid=FALSE ) {
8504
  $localtime = (( 'dtstart' == $caller ) && in_array( $objName, array( 'vtimezone', 'standard', 'daylight' ))) ? TRUE : FALSE;
8505
  iCalUtilityFunctions::_strDate2arr( $year );
8506
  if( iCalUtilityFunctions::_isArrayDate( $year )) {
8507
+ $input['value'] = iCalUtilityFunctions::_chkDateArr( $year, $parno );
8508
+ if( 100 > $input['value']['year'] )
8509
+ $input['value']['year'] += 2000;
8510
+ if( $localtime )
8511
+ unset( $month['VALUE'], $month['TZID'] );
8512
+ elseif( !isset( $month['TZID'] ) && isset( $tzid ))
8513
+ $month['TZID'] = $tzid;
8514
+ if( isset( $input['value']['tz'] ) && iCalUtilityFunctions::_isOffset( $input['value']['tz'] ))
8515
+ unset( $month['TZID'] );
8516
+ elseif( isset( $month['TZID'] ) && iCalUtilityFunctions::_isOffset( $month['TZID'] )) {
8517
+ $input['value']['tz'] = $month['TZID'];
8518
+ unset( $month['TZID'] );
8519
  }
8520
+ $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
8521
+ $hitval = ( isset( $input['value']['tz'] )) ? 7 : 6;
8522
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval );
8523
+ $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3, count( $input['value'] ), $parno );
8524
+ if(( 3 != $parno ) && isset( $input['value']['tz'] ) && ( 'Z' != $input['value']['tz'] ) && iCalUtilityFunctions::_isOffset( $input['value']['tz'] )) {
8525
+ $d = $input['value'];
8526
+ $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $d['tz'] );
8527
+ $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, $parno );
8528
+ unset( $input['value']['unparsedtext'], $input['params']['TZID'] );
8529
+ }
8530
+ if( isset( $input['value']['tz'] ) && !iCalUtilityFunctions::_isOffset( $input['value']['tz'] )) {
8531
+ $input['params']['TZID'] = $input['value']['tz'];
8532
+ unset( $input['value']['tz'] );
8533
+ }
8534
+ } // end if( iCalUtilityFunctions::_isArrayDate( $year ))
8535
  elseif( iCalUtilityFunctions::_isArrayTimestampDate( $year )) {
8536
  if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
8537
  $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
 
 
 
 
8538
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3 );
8539
+ $hitval = 7;
8540
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno );
8541
+ if( !isset( $input['params']['TZID'] ) && !empty( $tzid ))
8542
+ $input['params']['TZID'] = $tzid;
8543
+ if( isset( $year['tz'] )) {
8544
+ $parno = 6;
8545
+ if( !iCalUtilityFunctions::_isOffset( $year['tz'] ))
8546
+ $input['params']['TZID'] = $year['tz'];
 
 
8547
  }
8548
+ elseif( isset( $input['params']['TZID'] )) {
8549
+ $year['tz'] = $input['params']['TZID'];
8550
+ $parno = 6;
8551
+ if( iCalUtilityFunctions::_isOffset( $input['params']['TZID'] )) {
8552
+ unset( $input['params']['TZID'] );
8553
+ $parno = 7;
8554
+ }
 
8555
  }
8556
+ $input['value'] = iCalUtilityFunctions::_timestamp2date( $year, $parno );
8557
+ } // end elseif( iCalUtilityFunctions::_isArrayTimestampDate( $year ))
8558
+ elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18 [[[+/-]1234[56]] / timezone]
8559
+ if( $localtime )
8560
+ unset( $month['VALUE'], $month['TZID'] );
8561
+ elseif( !isset( $month['TZID'] ) && !empty( $tzid ))
8562
+ $month['TZID'] = $tzid;
8563
+ $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
8564
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7, $parno );
8565
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3, $parno, $parno );
8566
+ $input['value'] = iCalUtilityFunctions::_strdate2date( $year, $parno );
8567
  unset( $input['value']['unparsedtext'] );
8568
+ if( isset( $input['value']['tz'] )) {
8569
+ if( iCalUtilityFunctions::_isOffset( $input['value']['tz'] )) {
8570
+ $d = $input['value'];
8571
+ $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $d['tz'] );
8572
+ $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, 7 );
8573
+ unset( $input['value']['unparsedtext'], $input['params']['TZID'] );
8574
+ }
8575
+ else {
8576
+ $input['params']['TZID'] = $input['value']['tz'];
8577
+ unset( $input['value']['tz'] );
8578
+ }
8579
+ }
8580
+ elseif( isset( $input['params']['TZID'] ) && iCalUtilityFunctions::_isOffset( $input['params']['TZID'] )) {
8581
+ $d = $input['value'];
8582
+ $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $input['params']['TZID'] );
8583
+ $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, 7 );
8584
+ unset( $input['value']['unparsedtext'], $input['params']['TZID'] );
8585
+ }
8586
+ } // end elseif( 8 <= strlen( trim( $year )))
8587
  else {
8588
+ if( is_array( $params ))
 
8589
  $input['params'] = iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' ));
 
8590
  elseif( is_array( $tz )) {
8591
  $input['params'] = iCalUtilityFunctions::_setParams( $tz, array( 'VALUE' => 'DATE-TIME' ));
8592
  $tz = FALSE;
8595
  $input['params'] = iCalUtilityFunctions::_setParams( $hour, array( 'VALUE' => 'DATE-TIME' ));
8596
  $hour = $min = $sec = $tz = FALSE;
8597
  }
8598
+ if( $localtime )
8599
+ unset ( $input['params']['VALUE'], $input['params']['TZID'] );
8600
+ elseif( !isset( $tz ) && !isset( $input['params']['TZID'] ) && !empty( $tzid ))
8601
+ $input['params']['TZID'] = $tzid;
8602
+ elseif( isset( $tz ) && iCalUtilityFunctions::_isOffset( $tz ))
8603
+ unset( $input['params']['TZID'] );
8604
+ elseif( isset( $input['params']['TZID'] ) && iCalUtilityFunctions::_isOffset( $input['params']['TZID'] )) {
8605
+ $tz = $input['params']['TZID'];
8606
+ unset( $input['params']['TZID'] );
8607
  }
8608
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3 );
8609
+ $hitval = ( iCalUtilityFunctions::_isOffset( $tz )) ? 7 : 6;
8610
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno, $parno );
8611
  $input['value'] = array( 'year' => $year, 'month' => $month, 'day' => $day );
8612
  if( 3 != $parno ) {
8615
  $input['value']['sec'] = ( $sec ) ? $sec : '0';
8616
  if( !empty( $tz ))
8617
  $input['value']['tz'] = $tz;
8618
+ $strdate = iCalUtilityFunctions::_date2strdate( $input['value'], $parno );
8619
+ if( !empty( $tz ) && !iCalUtilityFunctions::_isOffset( $tz ))
8620
+ $strdate .= ( 'Z' == $tz ) ? $tz : ' '.$tz;
8621
+ $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, $parno );
8622
+ unset( $input['value']['unparsedtext'] );
8623
+ if( isset( $input['value']['tz'] )) {
8624
+ if( iCalUtilityFunctions::_isOffset( $input['value']['tz'] )) {
8625
+ $d = $input['value'];
8626
+ $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $d['tz'] );
8627
+ $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, 7 );
8628
+ unset( $input['value']['unparsedtext'], $input['params']['TZID'] );
8629
+ }
8630
+ else {
8631
+ $input['params']['TZID'] = $input['value']['tz'];
8632
+ unset( $input['value']['tz'] );
8633
+ }
8634
+ }
8635
+ elseif( isset( $input['params']['TZID'] ) && iCalUtilityFunctions::_isOffset( $input['params']['TZID'] )) {
8636
+ $d = $input['value'];
8637
+ $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $input['params']['TZID'] );
8638
+ $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, 7 );
8639
+ unset( $input['value']['unparsedtext'], $input['params']['TZID'] );
8640
+ }
8641
  }
8642
+ } // end else (i.e. using all arguments)
8643
+ if(( 3 == $parno ) || ( isset( $input['params']['VALUE'] ) && ( 'DATE' == $input['params']['VALUE'] ))) {
8644
  $input['params']['VALUE'] = 'DATE';
8645
+ unset( $input['value']['hour'], $input['value']['min'], $input['value']['sec'], $input['value']['tz'], $input['params']['TZID'] );
 
8646
  }
8647
+ elseif( isset( $input['params']['TZID'] )) {
8648
+ if(( 'UTC' == strtoupper( $input['params']['TZID'] )) || ( 'GMT' == strtoupper( $input['params']['TZID'] ))) {
8649
+ $input['value']['tz'] = 'Z';
 
 
 
 
 
 
 
 
 
 
 
 
 
8650
  unset( $input['params']['TZID'] );
8651
  }
8652
+ else
8653
+ unset( $input['value']['tz'] );
8654
+ }
8655
+ elseif( isset( $input['value']['tz'] )) {
8656
+ if(( 'UTC' == strtoupper( $input['value']['tz'] )) || ( 'GMT' == strtoupper( $input['value']['tz'] )))
8657
  $input['value']['tz'] = 'Z';
8658
+ if( 'Z' != $input['value']['tz'] ) {
8659
+ $input['params']['TZID'] = $input['value']['tz'];
8660
+ unset( $input['value']['tz'] );
8661
  }
8662
+ else
8663
+ unset( $input['params']['TZID'] );
8664
  }
8665
+ if( $localtime )
8666
+ unset( $input['value']['tz'], $input['params']['TZID'] );
8667
  return $input;
8668
  }
8669
  /**
8670
  * convert format for input date (UTC) to internal date with parameters
8671
  *
8672
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8673
+ * @since 2.14.4 - 2012-10-06
8674
  * @param mixed $year
8675
+ * @param mixed $month optional
8676
+ * @param int $day optional
8677
+ * @param int $hour optional
8678
+ * @param int $min optional
8679
+ * @param int $sec optional
8680
  * @param array $params optional
8681
  * @return array
8682
  */
8684
  $input = null;
8685
  iCalUtilityFunctions::_strDate2arr( $year );
8686
  if( iCalUtilityFunctions::_isArrayDate( $year )) {
8687
+ $input['value'] = iCalUtilityFunctions::_chkDateArr( $year, 7 );
8688
+ if( isset( $input['value']['year'] ) && ( 100 > $input['value']['year'] ))
8689
+ $input['value']['year'] += 2000;
8690
+ $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
8691
+ if( isset( $input['value']['tz'] ) && ( 'Z' != $input['value']['tz'] ) && iCalUtilityFunctions::_isOffset( $input['value']['tz'] )) {
8692
+ $d = $input['value'];
8693
+ $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $d['tz'] );
8694
+ $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, 7 );
8695
+ unset( $input['value']['unparsedtext'] );
8696
+ }
8697
  }
8698
  elseif( iCalUtilityFunctions::_isArrayTimestampDate( $year )) {
8699
+ $year['tz'] = 'UTC';
8700
  $input['value'] = iCalUtilityFunctions::_timestamp2date( $year, 7 );
8701
+ $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
8702
  }
8703
  elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18
8704
+ $input['value'] = iCalUtilityFunctions::_strdate2date( $year, 7 );
8705
  unset( $input['value']['unparsedtext'] );
8706
+ $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
8707
  }
8708
  else {
8709
  $input['value'] = array( 'year' => $year
8712
  , 'hour' => $hour
8713
  , 'min' => $min
8714
  , 'sec' => $sec );
8715
+ if( isset( $tz )) $input['value']['tz'] = $tz;
8716
+ if(( isset( $tz ) && iCalUtilityFunctions::_isOffset( $tz )) ||
8717
+ ( isset( $input['params']['TZID'] ) && iCalUtilityFunctions::_isOffset( $input['params']['TZID'] ))) {
8718
+ if( !isset( $tz ) && isset( $input['params']['TZID'] ) && iCalUtilityFunctions::_isOffset( $input['params']['TZID'] ))
8719
+ $input['value']['tz'] = $input['params']['TZID'];
8720
+ unset( $input['params']['TZID'] );
8721
+ $strdate = iCalUtilityFunctions::_date2strdate( $input['value'], 7 );
8722
+ $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, 7 );
8723
+ unset( $input['value']['unparsedtext'] );
8724
+ }
8725
  $input['params'] = iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' ));
8726
  }
8727
  $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7 ); // remove default
8728
+ if( !isset( $input['value']['hour'] )) $input['value']['hour'] = 0;
8729
+ if( !isset( $input['value']['min'] )) $input['value']['min'] = 0;
8730
+ if( !isset( $input['value']['sec'] )) $input['value']['sec'] = 0;
8731
+ $input['value']['tz'] = 'Z';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8732
  return $input;
8733
  }
8734
  /**
8797
  * step date, return updated date, array and timpstamp
8798
  *
8799
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8800
+ * @since 2.14.1 - 2012-09-24
8801
  * @param array $date, date to step
8802
+ * @param int $timestamp
8803
  * @param array $step, default array( 'day' => 1 )
8804
  * @return void
8805
  */
8806
  public static function _stepdate( &$date, &$timestamp, $step=array( 'day' => 1 )) {
8807
+ if( !isset( $date['hour'] )) $date['hour'] = 0;
8808
+ if( !isset( $date['min'] )) $date['min'] = 0;
8809
+ if( !isset( $date['sec'] )) $date['sec'] = 0;
8810
  foreach( $step as $stepix => $stepvalue )
8811
  $date[$stepix] += $stepvalue;
8812
+ $timestamp = mktime( $date['hour'], $date['min'], $date['sec'], $date['month'], $date['day'], $date['year'] );
8813
+ $d = date( 'Y-m-d-H-i-s', $timestamp);
8814
+ $d = explode( '-', $d );
8815
+ $date = array( 'year' => $d[0], 'month' => $d[1], 'day' => $d[2], 'hour' => $d[3], 'min' => $d[4], 'sec' => $d[5] );
8816
+ foreach( $date as $k => $v )
8817
+ $date[$k] = (int) $v;
8818
  }
8819
  /**
8820
  * convert a date from specific string to array format
8836
  $work = str_replace( '/', '', $work );
8837
  if( !ctype_digit( substr( $work, 0, 8 )))
8838
  return FALSE;
8839
+ $temp = array( 'year' => (int) substr( $work, 0, 4 )
8840
+ , 'month' => (int) substr( $work, 4, 2 )
8841
+ , 'day' => (int) substr( $work, 6, 2 ));
8842
+ if( !checkdate( $temp['month'], $temp['day'], $temp['year'] ))
8843
  return FALSE;
 
 
 
8844
  if( 8 == strlen( $work )) {
8845
  $input = $temp;
8846
  return TRUE;
8862
  return FALSE;
8863
  if( ctype_digit( substr( $work, 4, 2 ))) {
8864
  $temp['sec'] = substr( $work, 4, 2 );
8865
+ if(( 0 > $temp['sec'] ) || ( $temp['sec'] > 59 ))
8866
  return FALSE;
8867
  $len = 6;
8868
  }
8876
  return TRUE;
8877
  }
8878
  /**
8879
+ * ensures internal date-time/date format for input date-time/date in string fromat
8880
  *
8881
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8882
+ * @since 2.14.1 - 2012-10-07
8883
+ * Modified to also return original string value by Yitzchok Lavi <icalcreator@onebigsystem.com>
8884
+ * @param array $datetime
8885
+ * @param int $parno optional, default FALSE
8886
+ * @param moxed $wtz optional, default null
8887
  * @return array
8888
  */
8889
+ public static function _date_time_string( $datetime, $parno=FALSE ) {
8890
+ return iCalUtilityFunctions::_strdate2date( $datetime, $parno, null );
8891
+ }
8892
+ public static function _strdate2date( $datetime, $parno=FALSE, $wtz=null ) {
8893
+ // save original input string to return it later
8894
+ $unparseddatetime = $datetime;
8895
+ $datetime = (string) trim( $datetime );
8896
+ $tz = null;
8897
+ $offset = 0;
8898
+ $tzSts = FALSE;
8899
+ $len = strlen( $datetime );
8900
+ if( 'Z' == substr( $datetime, -1 )) {
8901
+ $tz = 'Z';
8902
+ $datetime = trim( substr( $datetime, 0, ( $len - 1 )));
8903
+ $tzSts = TRUE;
8904
+ $len = 88;
8905
+ }
8906
+ if( iCalUtilityFunctions::_isOffset( substr( $datetime, -5, 5 ))) { // [+/-]NNNN offset
8907
+ $tz = substr( $datetime, -5, 5 );
8908
+ $datetime = trim( substr( $datetime, 0, ($len - 5)));
8909
+ $len = strlen( $datetime );
8910
+ }
8911
+ elseif( iCalUtilityFunctions::_isOffset( substr( $datetime, -7, 7 ))) { // [+/-]NNNNNN offset
8912
+ $tz = substr( $datetime, -7, 7 );
8913
+ $datetime = trim( substr( $datetime, 0, ($len - 7)));
8914
+ $len = strlen( $datetime );
8915
+ }
8916
+ elseif( empty( $wtz ) && ctype_digit( substr( $datetime, 0, 4 )) && ctype_digit( substr( $datetime, -2, 2 )) && iCalUtilityFunctions::_strDate2arr( $datetime )) {
8917
+ $output = $datetime;
8918
+ if( !empty( $tz ))
8919
+ $output['tz'] = 'Z';
8920
+ $output['unparsedtext'] = $unparseddatetime;
8921
+ return $output;
8922
+ }
8923
+ else {
8924
+ $cx = $tx = 0; // find any trailing timezone or offset
8925
+ for( $cx = -1; $cx > ( 9 - $len ); $cx-- ) {
8926
+ $char = substr( $datetime, $cx, 1 );
8927
+ if(( ' ' == $char) || ctype_digit( $char ))
8928
+ break; // if exists, tz ends here.. . ?
8929
+ else
8930
+ $tx--; // tz length counter
8931
+ }
8932
+ if( 0 > $tx ) { // if any
8933
+ $tz = substr( $datetime, $tx );
8934
+ $datetime = trim( substr( $datetime, 0, $len + $tx ));
8935
+ $len = strlen( $datetime );
8936
+ }
8937
+ if(( 17 <= $len ) || // long textual datetime
8938
+ ( ctype_digit( substr( $datetime, 0, 8 )) && ( 'T' == substr( $datetime, 8, 1 )) && ctype_digit( substr( $datetime, -6, 6 ))) ||
8939
+ ( ctype_digit( substr( $datetime, 0, 14 )))) {
8940
+ $len = 88;
8941
+ $tzSts = TRUE;
8942
+ }
8943
+ else
8944
+ $tz = null; // no tz for Y-m-d dates
8945
+ }
8946
+ if( empty( $tz ) && !empty( $wtz ))
8947
+ $tz = $wtz;
8948
+ if( 17 >= $len ) // any Y-m-d textual date
8949
+ $tz = null;
8950
+ if( !empty( $tz ) && ( 17 < $len )) { // tz set AND long textual datetime
8951
+ if(( 'Z' != $tz ) && ( iCalUtilityFunctions::_isOffset( $tz ))) {
8952
+ $offset = (string) iCalUtilityFunctions::_tz2offset( $tz ) * -1;
8953
+ $tz = 'UTC';
8954
+ $tzSts = TRUE;
8955
+ }
8956
+ elseif( !empty( $wtz ))
8957
+ $tzSts = TRUE;
8958
+ $tz = trim( $tz );
8959
+ if(( 'Z' == $tz ) || ( 'GMT' == strtoupper( $tz )))
8960
+ $tz = 'UTC';
8961
+ if( 0 < substr_count( $datetime, '-' ))
8962
+ $datetime = str_replace( '-', '/', $datetime );
8963
+ try {
8964
+ $d = new DateTime( $datetime, new DateTimeZone( $tz ));
8965
+ if( 0 != $offset ) // adjust for offset
8966
+ $d->modify( $offset.' seconds' );
8967
+ $datestring = $d->format( 'Y-m-d-H-i-s' );
8968
+ unset( $d );
8969
+ }
8970
+ catch( Exception $e ) {
8971
+ $datestring = date( 'Y-m-d-H-i-s', strtotime( $datetime ));
8972
+ }
8973
+ } // end if( !empty( $tz ) && ( 17 < $len ))
8974
+ else
8975
+ $datestring = date( 'Y-m-d-H-i-s', strtotime( $datetime ));
8976
+ // echo "<tr><td>&nbsp;<td colspan='3'>_strdate2date input=$datetime, tz=$tz, offset=$offset, wtz=$wtz, len=$len, prepDate=$datestring\n";
8977
+ if( 'UTC' == $tz )
8978
+ $tz = 'Z';
8979
+ $d = explode( '-', $datestring );
8980
+ $output = array( 'year' => $d[0], 'month' => $d[1], 'day' => $d[2] );
8981
+ if((( FALSE !== $parno ) && ( 3 != $parno )) || // parno is set to 6 or 7
8982
+ (( FALSE === $parno ) && ( 'Z' == $tz )) || // parno is not set and UTC
8983
+ (( FALSE === $parno ) && ( 'Z' != $tz ) && ( 0 != $d[3] + $d[4] + $d[5] ) && ( 17 < $len ))) { // !parno and !UTC and 0 != hour+min+sec and long input text
8984
+ $output['hour'] = $d[3];
8985
+ $output['min'] = $d[4];
8986
+ $output['sec'] = $d[5];
8987
+ if(( $tzSts || ( 7 == $parno )) && !empty( $tz ))
8988
+ $output['tz'] = $tz;
8989
+ }
8990
+ // return original string in the array in case strtotime failed to make sense of it
8991
+ $output['unparsedtext'] = $unparseddatetime;
8992
+ return $output;
8993
+ }
8994
+ /**
8995
+ * convert timestamp to date array, default UTC or adjusted for offset/timezone
8996
+ *
8997
+ * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
8998
+ * @since 2.15.1 - 2012-10-17
8999
+ * @param mixed $timestamp
9000
+ * @param int $parno
9001
+ * @param string $wtz
9002
+ * @return array
9003
+ */
9004
+ public static function _timestamp2date( $timestamp, $parno=6, $wtz=null ) {
9005
  if( is_array( $timestamp )) {
9006
+ $tz = ( isset( $timestamp['tz'] )) ? $timestamp['tz'] : $wtz;
 
9007
  $timestamp = $timestamp['timestamp'];
9008
  }
9009
+ $tz = ( isset( $tz )) ? $tz : $wtz;
9010
+ if( empty( $tz ) || ( 'Z' == $tz ) || ( 'GMT' == strtoupper( $tz )))
9011
+ $tz = 'UTC';
9012
+ elseif( iCalUtilityFunctions::_isOffset( $tz )) {
9013
+ $offset = iCalUtilityFunctions::_tz2offset( $tz );
9014
+ $tz = 'UTC';
9015
+ }
9016
+ try {
9017
+ $d = new DateTime( "@$timestamp" ); // set UTC date
9018
+ if( isset( $offset ) && ( 0 != $offset )) // adjust for offset
9019
+ $d->modify( $offset.' seconds' );
9020
+ elseif( 'UTC' != $tz )
9021
+ $d->setTimezone( new DateTimeZone( $tz )); // convert to local date
9022
+ $date = $d->format( 'Y-m-d-H-i-s' );
9023
+ unset( $d );
9024
+ }
9025
+ catch( Exception $e ) {
9026
+ $date = date( 'Y-m-d-H-i-s', $timestamp );
9027
+ }
9028
+ $date = explode( '-', $date );
9029
+ $output = array( 'year' => $date[0], 'month' => $date[1], 'day' => $date[2] );
9030
  if( 3 != $parno ) {
9031
+ $output['hour'] = $date[3];
9032
+ $output['min'] = $date[4];
9033
+ $output['sec'] = $date[5];
9034
+ if( 'UTC' == $tz && ( !isset( $offset ) || ( 0 == $offset )))
9035
+ $output['tz'] = 'Z';
9036
  }
9037
  return $output;
9038
  }
9039
  /**
9040
+ * convert timestamp (seconds) to duration in array format
9041
  *
9042
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
9043
  * @since 2.6.23 - 2010-10-23
9060
  * transforms a dateTime from a timezone to another using PHP DateTime and DateTimeZone class (PHP >= PHP 5.2.0)
9061
  *
9062
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
9063
+ * @since 2.15.1 - 2012-10-17
9064
  * @param mixed $date, date to alter
9065
+ * @param string $tzFrom, PHP valid 'from' timezone
9066
+ * @param string $tzTo, PHP valid 'to' timezone, default 'UTC'
9067
  * @param string $format, date output format, default 'Ymd\THis'
9068
  * @return bool
9069
  */
9070
  public static function transformDateTime( & $date, $tzFrom, $tzTo='UTC', $format = 'Ymd\THis' ) {
9071
+ if( is_array( $date ) && isset( $date['timestamp'] )) {
9072
+ try {
9073
+ $d = new DateTime( "@{$date['timestamp']}" ); // set UTC date
9074
+ $d->setTimezone(new DateTimeZone( $tzFrom )); // convert to 'from' date
9075
+ }
9076
+ catch( Exception $e ) { return FALSE; }
9077
+ }
9078
+ else {
9079
+ if( iCalUtilityFunctions::_isArrayDate( $date )) {
9080
+ if( isset( $date['tz'] ))
9081
+ unset( $date['tz'] );
9082
+ $date = iCalUtilityFunctions::_date2strdate( iCalUtilityFunctions::_chkDateArr( $date ));
9083
+ }
9084
  if( 'Z' == substr( $date, -1 ))
9085
  $date = substr( $date, 0, ( strlen( $date ) - 2 ));
9086
+ try { $d = new DateTime( $date, new DateTimeZone( $tzFrom )); }
9087
+ catch( Exception $e ) { return FALSE; }
 
 
 
 
 
 
 
 
 
9088
  }
9089
+ try { $d->setTimezone( new DateTimeZone( $tzTo )); }
9090
+ catch( Exception $e ) { return FALSE; }
9091
  $date = $d->format( $format );
9092
  return TRUE;
9093
  }
9094
  /**
9095
+ * convert offset, [+/-]HHmm[ss], to seconds used when correcting UTC to localtime or v.v.
9096
  *
9097
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
9098
  * @since 2.11.4 - 2012-01-11
9102
  public static function _tz2offset( $tz ) {
9103
  $tz = trim( (string) $tz );
9104
  $offset = 0;
9105
+ if((( 5 != strlen( $tz )) && ( 7 != strlen( $tz ))) ||
9106
  (( '+' != substr( $tz, 0, 1 )) && ( '-' != substr( $tz, 0, 1 ))) ||
9107
  (( '0000' >= substr( $tz, 1, 4 )) && ( '9999' < substr( $tz, 1, 4 ))) ||
9108
+ (( 7 == strlen( $tz )) && ( '00' > substr( $tz, 5, 2 )) && ( '99' < substr( $tz, 5, 2 ))))
9109
  return $offset;
9110
  $hours2sec = (int) substr( $tz, 1, 2 ) * 3600;
9111
  $min2sec = (int) substr( $tz, 3, 2 ) * 60;
9259
  * format iCal XML output, rfc6321, using PHP SimpleXMLElement
9260
  *
9261
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
9262
+ * @since 2.15.6 - 2012-10-19
9263
  * @param object $calendar, iCalcreator vcalendar instance reference
9264
  * @return string
9265
  */
9283
  /** prepare to fix components with properties */
9284
  $components = $vcalendar->addChild( 'components' );
9285
  $comps = array( 'vtimezone', 'vevent', 'vtodo', 'vjournal', 'vfreebusy' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9286
  foreach( $comps as $compName ) {
9287
  switch( $compName ) {
9288
  case 'vevent':
 
 
 
 
9289
  case 'vtodo':
 
9290
  $subComps = array( 'valarm' );
 
9291
  break;
9292
  case 'vjournal':
 
 
 
 
9293
  case 'vfreebusy':
 
9294
  $subComps = array();
 
9295
  break;
9296
  case 'vtimezone':
 
9297
  $subComps = array( 'standard', 'daylight' );
 
9298
  break;
9299
  } // end switch( $compName )
9300
  /** fix component properties */
9301
  while( FALSE !== ( $component = $calendar->getComponent( $compName ))) {
9302
  $child = $components->addChild( $compName );
9303
  $properties = $child->addChild( 'properties' );
9304
+ $langComp = $component->getConfig( 'language' );
9305
+ $props = $component->getConfig( 'setPropertyNames' );
9306
  foreach( $props as $prop ) {
9307
+ switch( strtolower( $prop )) {
9308
  case 'attach': // may occur multiple times, below
9309
  while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) {
9310
  $type = ( isset( $content['params']['VALUE'] ) && ( 'BINARY' == $content['params']['VALUE'] )) ? 'binary' : 'uri';
9327
  while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) {
9328
  $type = ( isset( $content['params']['VALUE'] ) && ( 'DATE' == $content['params']['VALUE'] )) ? 'date' : 'date-time';
9329
  unset( $content['params']['VALUE'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9330
  _addXMLchild( $properties, $prop, $type, $content['value'], $content['params'] );
9331
  }
9332
  break;
9333
  case 'freebusy':
9334
+ while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) {
9335
+ if( is_array( $content ) && isset( $content['value']['fbtype'] )) {
9336
+ $content['params']['FBTYPE'] = $content['value']['fbtype'];
9337
+ unset( $content['value']['fbtype'] );
9338
+ }
9339
  _addXMLchild( $properties, $prop, 'period', $content['value'], $content['params'] );
9340
+ }
9341
  break;
9342
  case 'request-status':
9343
  while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) {
9359
  elseif( 'PERIOD' == $content['params']['VALUE'] )
9360
  $type = 'period';
9361
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9362
  unset( $content['params']['VALUE'] );
9363
  _addXMLchild( $properties, $prop, $type, $content['value'], $content['params'] );
9364
  }
9393
  case 'due':
9394
  case 'recurrence-id':
9395
  if( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) {
9396
+ $type = ( isset( $content['params']['VALUE'] ) && ( 'DATE' == $content['params']['VALUE'] )) ? 'date' : 'date-time';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9397
  unset( $content['params']['VALUE'] );
9398
  if(( isset( $content['params']['TZID'] ) && empty( $content['params']['TZID'] )) || @is_null( $content['params']['TZID'] ))
9399
  unset( $content['params']['TZID'] );
9402
  unset( $utcDate );
9403
  break;
9404
  case 'duration':
9405
+ if( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) {
9406
+ if( !isset( $content['value']['relatedStart'] ) || ( TRUE !== $content['value']['relatedStart'] ))
9407
+ $content['params']['RELATED'] = 'END';
9408
  _addXMLchild( $properties, $prop, 'duration', $content['value'], $content['params'] );
9409
+ }
9410
  break;
9411
  case 'rrule':
9412
  while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE )))
9460
  /** fix subComponent properties, if any */
9461
  foreach( $subComps as $subCompName ) {
9462
  while( FALSE !== ( $subcomp = $component->getComponent( $subCompName ))) {
9463
+ $child2 = $child->addChild( $subCompName );
9464
+ $properties = $child2->addChild( 'properties' );
9465
+ $langComp = $subcomp->getConfig( 'language' );
9466
+ $subCompProps = $subcomp->getConfig( 'setPropertyNames' );
9467
  foreach( $subCompProps as $prop ) {
9468
+ switch( strtolower( $prop )) {
9469
  case 'attach': // may occur multiple times, below
9470
  while( FALSE !== ( $content = $subcomp->getProperty( $prop, FALSE, TRUE ))) {
9471
  $type = ( isset( $content['params']['VALUE'] ) && ( 'BINARY' == $content['params']['VALUE'] )) ? 'binary' : 'uri';
9505
  elseif( 'PERIOD' == $content['params']['VALUE'] )
9506
  $type = 'period';
9507
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9508
  unset( $content['params']['VALUE'] );
9509
  _addXMLchild( $properties, $prop, $type, $content['value'], $content['params'] );
9510
  }
9546
  isset( $content['value']['month'] ) &&
9547
  isset( $content['value']['day'] ))
9548
  $type = 'date-time';
9549
+ else {
9550
  $type = 'duration';
9551
+ if( !isset( $content['value']['relatedStart'] ) || ( TRUE !== $content['value']['relatedStart'] ))
9552
+ $content['params']['RELATED'] = 'END';
9553
+ }
9554
  _addXMLchild( $properties, $prop, $type, $content['value'], $content['params'] );
9555
  }
9556
  break;
9575
  * Add children to a SimpleXMLelement
9576
  *
9577
  * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
9578
+ * @since 2.15.5 - 2012-10-19
9579
  * @param object $parent, reference to a SimpleXMLelement node
9580
  * @param string $name, new element node name
9581
  * @param string $type, content type, subelement(-s) name
9585
  */
9586
  function _addXMLchild( & $parent, $name, $type, $content, $params=array()) {
9587
  /** create new child node */
9588
+ $name = strtolower( $name );
9589
+ $child = $parent->addChild( $name );
 
 
 
 
9590
  if( isset( $params['VALUE'] ))
9591
  unset( $params['VALUE'] );
 
 
9592
  if( !empty( $params )) {
9593
  $parameters = $child->addChild( 'parameters' );
9594
  foreach( $params as $param => $parVal ) {
9653
  break;
9654
  case 'duration':
9655
  $output = (( 'trigger' == $name ) && ( FALSE !== $content['before'] )) ? '-' : '';
9656
+ $v = $child->addChild( $type, $output.iCalUtilityFunctions::_duration2str( $content ) );
9657
  break;
9658
  case 'geo':
9659
  $v1 = $child->addChild( 'latitude', number_format( (float) $content['latitude'], 6, '.', '' ));
9678
  $v2 = $v1->addChild( 'end', $str );
9679
  }
9680
  else
9681
+ $v2 = $v1->addChild( 'duration', iCalUtilityFunctions::_duration2str( $period[1] ));
9682
  }
9683
  break;
9684
  case 'recur':
10062
  $iCal->setProperty( $propName, $value, $params );
10063
  }
10064
  }
10065
+ /*********************************************************************************/
10066
+ /* Additional functions to use with vtimezone components */
10067
+ /*********************************************************************************/
10068
  /**
 
10069
  * For use with
10070
  * iCalcreator (kigkonsult.se/iCalcreator/index.php)
10071
  * copyright (c) 2011 Yitzchok Lavi
10352
  }
10353
  }
10354
  return $tzdates;
10355
+ }
lib/{iCalcreator-2.10 → iCalcreator-2.16}/lgpl.txt RENAMED
File without changes
readme.txt CHANGED
@@ -1,10 +1,10 @@
1
  === All-in-One Event Calendar ===
2
  Contributors: theseed, hubrik, vtowel, yani.iliev, jbutkus
3
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=9JJMUW48W2ED8
4
- Tags: calendar, event, events, ics, ics calendar, ical-feed, ics feed, wordpress ics importer, wordpress ical importer, upcoming events, todo, notes, journal, freebusy, availability, web calendar, web events, webcal, google calendar, ical, iCalendar, all-in-one, ai1ec, google calendar sync, ical sync, events sync, holiday calendar, calendar 2011, events 2011, widget, events widget, upcoming events widget, calendar widget, agenda widget
5
  Requires at least: 3.2
6
  Tested up to: 3.6
7
- Stable tag: 1.10.2
8
  License: GNU General Public License, version 3 (GPL-3.0)
9
 
10
  A calendar system with month, week, day, agenda views; upcoming events widget, color-coded categories, recurrence, and import/export of .ics feeds.
@@ -54,11 +54,11 @@ http://www.youtube.com/watch?v=XJ-KHOqBKuQ
54
 
55
  = Helpful Links =
56
 
57
- * [**Get help from our Help Desk »**](http://help.time.ly)
58
 
59
  == Frequently Asked Questions ==
60
 
61
- [**Get help from our Help Desk »**](http://help.time.ly)
62
 
63
  = Shortcodes =
64
 
@@ -81,7 +81,19 @@ http://www.youtube.com/watch?v=XJ-KHOqBKuQ
81
  * Filter by post ids (separate ids by comma): **[ai1ec post_id="1, 2"]**
82
 
83
  == Changelog ==
84
- = Version 1.10.2
 
 
 
 
 
 
 
 
 
 
 
 
85
  * Fixed issue with upgrading to standard. Now it downloads latest standard
86
 
87
  = Version 1.10.1 =
1
  === All-in-One Event Calendar ===
2
  Contributors: theseed, hubrik, vtowel, yani.iliev, jbutkus
3
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=9JJMUW48W2ED8
4
+ Tags: calendar, events, ics, ics feed, wordpress ical importer, google calendar, ical, iCalendar, all-in-one, events sync, events widget, calendar widget
5
  Requires at least: 3.2
6
  Tested up to: 3.6
7
+ Stable tag: 1.10.3
8
  License: GNU General Public License, version 3 (GPL-3.0)
9
 
10
  A calendar system with month, week, day, agenda views; upcoming events widget, color-coded categories, recurrence, and import/export of .ics feeds.
54
 
55
  = Helpful Links =
56
 
57
+ * [**Get help from our Help Desk »**](http://support.time.ly)
58
 
59
  == Frequently Asked Questions ==
60
 
61
+ [**Get help from our Help Desk »**](http://support.time.ly)
62
 
63
  = Shortcodes =
64
 
81
  * Filter by post ids (separate ids by comma): **[ai1ec post_id="1, 2"]**
82
 
83
  == Changelog ==
84
+
85
+ = Version 1.10.3 =
86
+ * Removed GPL license incompatible library
87
+ * Modified notices to be displayed only on calendar, Plugins and
88
+ Updates windows in admin area
89
+ * Modified themes installation page to make it possible to postpone
90
+ action required to take on it
91
+ * Disabled automatic upgrades to Standard version to comply with
92
+ WordPress.org plugins directory listing rules
93
+ * Fixed an issue that caused the plugin to generate statistics reports
94
+ too frequently resulting in higher than expected server loads
95
+
96
+ = Version 1.10.2 =
97
  * Fixed issue with upgrading to standard. Now it downloads latest standard
98
 
99
  = Version 1.10.1 =
themes-ai1ec/vortex/agenda-widget.php CHANGED
@@ -67,7 +67,6 @@
67
  <i class="timely-icon-forward"></i>
68
  </a>
69
  <?php endif; ?>
70
-
71
  <?php if( $show_subscribe_buttons ): ?>
72
  <span class="ai1ec-subscribe-buttons pull-left">
73
  <a class="btn btn-mini ai1ec-subscribe"
67
  <i class="timely-icon-forward"></i>
68
  </a>
69
  <?php endif; ?>
 
70
  <?php if( $show_subscribe_buttons ): ?>
71
  <span class="ai1ec-subscribe-buttons pull-left">
72
  <a class="btn btn-mini ai1ec-subscribe"