Plugin Directory

Changeset 1370585


Ignore:
Timestamp:
03/14/2016 10:19:28 AM (10 years ago)
Author:
wpicalavailability
Message:
  • Updated ics parser class
  • Fixed a compatibility issue with the premium version
Location:
wp-ical-availability
Files:
325 added
8 edited

Legend:

Unmodified
Added
Removed
  • wp-ical-availability/trunk/controllers/calendar/calendar-save.php

    r1366824 r1370585  
    22global $wpdb;
    33
    4 if(isset($_POST['icalendar_feed'])) $calendarOptions['icalendar_feed'] = esc_url( sanitize_text_field($_POST['icalendar_feed']));
     4if(isset($_POST['icalendar_feed'])) $calendarOptions['icalendar_feed'][0] = esc_url( sanitize_text_field($_POST['icalendar_feed']));
    55$calendarTitle = sanitize_text_field($_POST['calendarTitle']);
    66
  • wp-ical-availability/trunk/include/calendarCore.php

    r1363945 r1370585  
    2020        $ical   = new ICal($calendarFeed);
    2121        $events = $ical->events();
     22       
    2223        if($events) foreach($events as $event){
    23            
     24            //print_r($event);
    2425            $start = strtotime($event['DTSTART']);
    2526            $end = strtotime($event['DTEND']) - 60;
     
    3031           
    3132        }
     33       
    3234        $calendarData = json_encode($calendarData);
    3335    }
  • wp-ical-availability/trunk/include/calendarFunctions.php

    r1363945 r1370585  
    5050        $output .= ".wpia-calendar-".$calendarID." .wpia-day-split-bottom-available {display:none ;} ";
    5151       
    52         $bookedColor = (!empty($calendarOptions['booked_color'])) ? $calendarOptions['booked_color'] : '#DDFFCC';
     52        $bookedColor = (!empty($calendarOptions['booked_color'])) ? $calendarOptions['booked_color'] : '#FFC0BD';
    5353        $output .= ".wpia-calendar-".$calendarID." .status-booked {background-color: ".$bookedColor." ;}";
    5454        $output .= ".wpia-calendar-".$calendarID." .wpia-day-split-top-booked {display:none ;} ";
  • wp-ical-availability/trunk/include/class.iCalReader.php

    r1363945 r1370585  
    11<?php
    22/**
    3  * This PHP-Class should only read a iCal-File (*.ics), parse it and give an
     3 * This PHP class should only read an iCal file (*.ics), parse it and return an
    44 * array with its content.
    55 *
     
    77 *
    88 * @category Parser
    9  * @package  Ics-parser
     9 * @package  ics-parser
    1010 * @author   Martin Thoma <info@martin-thoma.de>
    11  * @license  http://www.opensource.org/licenses/mit-license.php  MIT License
    12  * @version  SVN: <svn_id>
    13  * @link     http://code.google.com/p/ics-parser/
    14  * @example  $ical = new ical('MyCal.ics');
    15  *           print_r( $ical->events() );
     11 * @license  http://www.opensource.org/licenses/mit-license.php MIT License
     12 * @link     https://github.com/MartinThoma/ics-parser/
     13 * @example  $ical = new ical('MyCal.ics'); print_r($ical->events());
     14 * @version  1.0.2
    1615 */
    1716
     17/**
     18 * This is the ICal class
     19 *
     20 * @param {string} filename The name of the file which should be parsed
     21 * @constructor
     22 */
    1823class ICal
    1924{
    20     /* How many ToDos are in this ical? */
    21     public  /** @type {int} */ $todo_count = 0;
    22 
    23     /* How many events are in this ical? */
    24     public  /** @type {int} */ $event_count = 0;
     25    /* How many ToDos are in this iCal? */
     26    public /** @type {int} */ $todo_count = 0;
     27
     28    /* How many events are in this iCal? */
     29    public /** @type {int} */ $event_count = 0;
     30
     31    /* How many freebusy are in this iCal? */
     32    public /** @type {int} */ $freebusy_count = 0;
    2533
    2634    /* The parsed calendar */
     
    2836
    2937    /* Which keyword has been added to cal at last? */
    30     private /** @type {string} */ $_lastKeyWord;
    31 
    32     /**
    33      * Creates the iCal-Object
    34      *
    35      * @param {string} $filename The path to the iCal-file
    36      *
    37      * @return Object The iCal-Object
    38      */
    39     public function __construct($filename)
    40     {
    41         if (!$filename && filter_var($filename, FILTER_VALIDATE_URL) === false) {
     38    private /** @type {string} */ $last_keyword;
     39
     40    /* The value in years to use for indefinite, recurring events */
     41    public /** @type {int} */ $default_span = 2;
     42
     43    /**
     44     * Creates the iCal Object
     45     *
     46     * @param {mixed} $filename The path to the iCal-file or an array of lines from an iCal file
     47     *
     48     * @return Object The iCal Object
     49     */
     50    public function __construct($filename=false)
     51    {
     52        if (!$filename) {
    4253            return false;
    43         }
    44        
    45         $reponse = @file_get_contents($filename);
    46        
    47         if($reponse === FALSE) { //reading file for certain websites like airBnb
    48             $curl_handle=curl_init();
    49             curl_setopt($curl_handle, CURLOPT_URL, $filename);
    50             curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 2);
    51             curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
    52             $reponse = curl_exec($curl_handle);
    53 
    54             curl_close($curl_handle);
    55         }
    56        
    57         $lines = explode("\n", $reponse);
    58 
     54        }   
     55               
     56        $agent = "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)";
     57        $curl_handle=curl_init();
     58        curl_setopt($curl_handle, CURLOPT_USERAGENT, $agent);
     59        curl_setopt($curl_handle, CURLOPT_URL, $filename);
     60        curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 1);
     61        curl_setopt($curl_handle, CURLOPT_TIMEOUT, 2);
     62        curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
     63        curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
     64       
     65        $contents = curl_exec($curl_handle);
     66       
     67        curl_close($curl_handle);
     68
     69        $lines = explode("\n", $contents);
     70
     71        return $this->initLines($lines);
     72    }
     73
     74
     75    /**
     76     * Initializes lines from a URL
     77     *
     78     * @url {string} $url The url of the ical file to download and initialize.  Unless you know what you're doing, it should begin with "http://"
     79     *
     80     * @return Object The iCal Object
     81     */
     82    public function initURL($url)
     83    {
     84       
     85    }
     86
     87
     88    /**
     89     * Initializes lines from file
     90     *
     91     * @param {array} $lines The lines to initialize
     92     *
     93     * @return Object The iCal Object
     94     */
     95    public function initLines($lines)
     96    {
    5997        if (stristr($lines[0], 'BEGIN:VCALENDAR') === false) {
    6098            return false;
    6199        } else {
    62             // TODO: Fix multiline-description problem (see http://tools.ietf.org/html/rfc2445#section-4.8.1.5)
    63100            foreach ($lines as $line) {
    64                 $line = trim($line);
     101                $line = rtrim($line); // Trim trailing whitespace
    65102                $add  = $this->keyValueFromString($line);
     103
    66104                if ($add === false) {
    67                     $this->addCalendarComponentWithKeyAndValue($type, false, $line);
     105                    $this->addCalendarComponentWithKeyAndValue($component, false, $line);
    68106                    continue;
    69                 }
    70 
    71                 list($keyword, $value) = $add;
    72 
    73                 switch ($line) {
    74                 // http://www.kanzaki.com/docs/ical/vtodo.html
    75                 case "BEGIN:VTODO":
    76                     $this->todo_count++;
    77                     $type = "VTODO";
    78                     break;
    79 
    80                 // http://www.kanzaki.com/docs/ical/vevent.html
    81                 case "BEGIN:VEVENT":
    82                     //echo "vevent gematcht";
    83                     $this->event_count++;
    84                     $type = "VEVENT";
    85                     break;
    86 
    87                 //all other special strings
    88                 case "BEGIN:VCALENDAR":
    89                 case "BEGIN:DAYLIGHT":
    90                     // http://www.kanzaki.com/docs/ical/vtimezone.html
    91                 case "BEGIN:VTIMEZONE":
    92                 case "BEGIN:STANDARD":
    93                     $type = $value;
    94                     break;
    95                 case "END:VTODO": // end special text - goto VCALENDAR key
    96                 case "END:VEVENT":
    97                 case "END:VCALENDAR":
    98                 case "END:DAYLIGHT":
    99                 case "END:VTIMEZONE":
    100                 case "END:STANDARD":
    101                     $type = "VCALENDAR";
    102                     break;
    103                 default:
    104                     $this->addCalendarComponentWithKeyAndValue($type,
    105                                                                $keyword,
    106                                                                $value);
    107                     break;
    108                 }
     107                }
     108
     109                $keyword = $add[0];
     110                $values = $add[1]; // Could be an array containing multiple values
     111
     112                if (!is_array($values)) {
     113                    if (!empty($values)) {
     114                        $values = array($values); // Make an array as not already
     115                        $blank_array = array(); // Empty placeholder array
     116                        array_push($values, $blank_array);
     117                    } else {
     118                        $values = array(); // Use blank array to ignore this line
     119                    }
     120                } else if(empty($values[0])) {
     121                    $values = array(); // Use blank array to ignore this line
     122                }
     123
     124                $values = array_reverse($values); // Reverse so that our array of properties is processed first
     125
     126                foreach ($values as $value) {
     127                    switch ($line) {
     128                        // http://www.kanzaki.com/docs/ical/vtodo.html
     129                        case 'BEGIN:VTODO':
     130                            $this->todo_count++;
     131                            $component = 'VTODO';
     132                            break;
     133
     134                        // http://www.kanzaki.com/docs/ical/vevent.html
     135                        case 'BEGIN:VEVENT':
     136                            if (!is_array($value)) {
     137                                $this->event_count++;
     138                            }
     139                            $component = 'VEVENT';
     140                            break;
     141
     142                        // http://www.kanzaki.com/docs/ical/vfreebusy.html
     143                        case 'BEGIN:VFREEBUSY':
     144                            $this->freebusy_count++;
     145                            $component = 'VFREEBUSY';
     146                            break;
     147
     148                        // All other special strings
     149                        case 'BEGIN:VCALENDAR':
     150                        case 'BEGIN:DAYLIGHT':
     151                            // http://www.kanzaki.com/docs/ical/vtimezone.html
     152                        case 'BEGIN:VTIMEZONE':
     153                        case 'BEGIN:STANDARD':
     154                        case 'BEGIN:VALARM':
     155                            $component = $value;
     156                            break;
     157                        case 'END:VALARM':
     158                        case 'END:VTODO': // End special text - goto VCALENDAR key
     159                        case 'END:VEVENT':
     160                        case 'END:VFREEBUSY':
     161                        case 'END:VCALENDAR':
     162                        case 'END:DAYLIGHT':
     163                        case 'END:VTIMEZONE':
     164                        case 'END:STANDARD':
     165                            $component = 'VCALENDAR';
     166                            break;
     167                        default:
     168                            $this->addCalendarComponentWithKeyAndValue($component, $keyword, $value);
     169                            break;
     170                    }
     171                }
    109172            }
    110             return $this->cal;
    111         }
    112     }
    113 
    114     /**
     173            $this->process_recurrences();
     174            return $this->cal;
     175        }
     176    }
     177
     178    /**
    115179     * Add to $this->ical array one value and key.
    116      * 
    117      * @param {string} $component This could be VTODO, VEVENT, VCALENDAR, ... 
     180     *
     181     * @param {string} $component This could be VTODO, VEVENT, VCALENDAR, ...
    118182     * @param {string} $keyword   The keyword, for example DTSTART
    119183     * @param {string} $value     The value, for example 20110105T090000Z
    120184     *
    121185     * @return {None}
    122      */ 
    123     public function addCalendarComponentWithKeyAndValue($component,
    124                                                         $keyword,
    125                                                         $value)
    126     {
    127         if ($keyword == false) {
    128             $keyword = $this->last_keyword;
    129             switch ($component) {
    130             case 'VEVENT':
    131                 $value = $this->cal[$component][$this->event_count - 1][$keyword].$value;
     186     */
     187    public function addCalendarComponentWithKeyAndValue($component, $keyword, $value)
     188    {
     189        if ($keyword == false) {
     190            $keyword = $this->last_keyword;
     191        }
     192
     193        switch ($component) {
     194            case 'VTODO':
     195                $this->cal[$component][$this->todo_count - 1][$keyword] = $value;
    132196                break;
    133             case 'VTODO' :
    134                 $value = $this->cal[$component][$this->todo_count - 1][$keyword].$value;
     197            case 'VEVENT':
     198                if (!isset($this->cal[$component][$this->event_count - 1][$keyword . '_array'])) {
     199                    $this->cal[$component][$this->event_count - 1][$keyword . '_array'] = array(); // Create array()
     200                }
     201
     202                if (is_array($value)) {
     203                    array_push($this->cal[$component][$this->event_count - 1][$keyword . '_array'], $value); // Add array of properties to the end
     204                } else {
     205                    if (!isset($this->cal[$component][$this->event_count - 1][$keyword])) {
     206                        $this->cal[$component][$this->event_count - 1][$keyword] = $value;
     207                    }
     208
     209                    $this->cal[$component][$this->event_count - 1][$keyword . '_array'][] = $value;
     210
     211                    // Glue back together for multi-line content
     212                    if ($this->cal[$component][$this->event_count - 1][$keyword] != $value) {
     213                        $ord = (isset($value[0])) ? ord($value[0]) : NULL; // First char
     214
     215                        if(in_array($ord, array(9, 32))){ // Is space or tab?
     216                            $value = substr($value, 1); // Only trim the first character
     217                        }
     218
     219                        if(is_array($this->cal[$component][$this->event_count - 1][$keyword . '_array'][1])){ // Account for multiple definitions of current keyword (e.g. ATTENDEE)
     220                            $this->cal[$component][$this->event_count - 1][$keyword] .= ';' . $value; // Concat value *with separator* as content spans multiple lines
     221                        } else {
     222                            $this->cal[$component][$this->event_count - 1][$keyword] .= $value; // Concat value as content spans multiple lines
     223                        }
     224                    }
     225                }
    135226                break;
    136             }
    137         }
    138        
    139         if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) {
    140             $keyword = explode(";", $keyword);
    141             $keyword = $keyword[0];
    142         }
    143 
    144         switch ($component) {
    145         case "VTODO":
    146             $this->cal[$component][$this->todo_count - 1][$keyword] = $value;
    147             //$this->cal[$component][$this->todo_count]['Unix'] = $unixtime;
    148             break;
    149         case "VEVENT":
    150             $this->cal[$component][$this->event_count - 1][$keyword] = $value;
    151             break;
    152         default:
    153             $this->cal[$component][$keyword] = $value;
    154             break;
    155         }
    156         $this->last_keyword = $keyword;
     227            case 'VFREEBUSY':
     228                $this->cal[$component][$this->freebusy_count - 1][$keyword] = $value;
     229                break;
     230            default:
     231                $this->cal[$component][$keyword] = $value;
     232                break;
     233        }
     234        $this->last_keyword = $keyword;
    157235    }
    158236
     
    164242     * @return {array} array("VCALENDAR", "Begin")
    165243     */
    166     public function keyValueFromString($text)
    167     {
    168         preg_match("/([^:]+)[:]([\w\W]*)/", $text, $matches);
     244    public function keyValueFromString($text)
     245    {
     246        // Match colon separator outside of quoted substrings
     247        // Fallback to nearest semicolon outside of quoted substrings, if colon cannot be found
     248        // Do not try and match within the value paired with the keyword
     249        preg_match('/(.*?)(?::(?=(?:[^"]*"[^"]*")*[^"]*$)|;(?=[^:]*$))([\w\W]*)/', $text, $matches);
     250
    169251        if (count($matches) == 0) {
    170252            return false;
    171253        }
    172         $matches = array_splice($matches, 1, 2);
    173         return $matches;
    174     }
    175 
    176     /**
    177      * Return Unix timestamp from ical date time format
    178      *
     254
     255        if (preg_match('/^([A-Z-]+)([;][\w\W]*)?$/', $matches[1])) {
     256            $matches = array_splice($matches, 1, 2); // Remove first match and re-align ordering
     257
     258            // Process properties
     259            if (preg_match('/([A-Z-]+)[;]([\w\W]*)/', $matches[0], $properties)) {
     260                array_shift($properties); // Remove first match
     261                $matches[0] = $properties[0]; // Fix to ignore everything in keyword after a ; (e.g. Language, TZID, etc.)
     262                array_shift($properties); // Repeat removing first match
     263
     264                $formatted = array();
     265                foreach ($properties as $property) {
     266                    preg_match_all('~[^\r\n";]+(?:"[^"\\\]*(?:\\\.[^"\\\]*)*"[^\r\n";]*)*~', $property, $attributes); // Match semicolon separator outside of quoted substrings
     267                    $attributes = (sizeof($attributes) == 0) ? array($property) : reset($attributes); // Remove multi-dimensional array and use the first key
     268
     269                    foreach ($attributes as $attribute) {
     270                        preg_match_all('~[^\r\n"=]+(?:"[^"\\\]*(?:\\\.[^"\\\]*)*"[^\r\n"=]*)*~', $attribute, $values); // Match equals sign separator outside of quoted substrings
     271                        $value = (sizeof($values) == 0) ? NULL : reset($values); // Remove multi-dimensional array and use the first key
     272
     273                        if (is_array($value) && isset($value[1])) {
     274                            $formatted[$value[0]] = trim($value[1], '"'); // Remove double quotes from beginning and end only
     275                        }
     276                    }
     277                }
     278
     279                $properties[0] = $formatted; // Assign the keyword property information
     280
     281                array_unshift($properties, $matches[1]); // Add match to beginning of array
     282                $matches[1] = $properties;
     283            }
     284
     285            return $matches;
     286        } else {
     287            return false; // Ignore this match
     288        }
     289    }
     290
     291    /**
     292     * Return Unix timestamp from iCal date time format
     293     *
    179294     * @param {string} $icalDate A Date in the format YYYYMMDD[T]HHMMSS[Z] or
    180295     *                           YYYYMMDD[T]HHMMSS
    181296     *
    182      * @return {int} 
    183      */ 
    184     public function iCalDateToUnixTimestamp($icalDate) 
    185     { 
    186         $icalDate = str_replace('T', '', $icalDate); 
    187         $icalDate = str_replace('Z', '', $icalDate); 
     297     * @return {int}
     298     */
     299    public function iCalDateToUnixTimestamp($icalDate)
     300    {
     301        $icalDate = str_replace('T', '', $icalDate);
     302        $icalDate = str_replace('Z', '', $icalDate);
    188303
    189304        $pattern  = '/([0-9]{4})';   // 1: YYYY
     
    193308        $pattern .= '([0-9]{0,2})';  // 5: MM
    194309        $pattern .= '([0-9]{0,2})/'; // 6: SS
    195         preg_match($pattern, $icalDate, $date); 
     310        preg_match($pattern, $icalDate, $date);
    196311
    197312        // Unix timestamp can't represent dates before 1970
    198313        if ($date[1] <= 1970) {
    199314            return false;
    200         } 
     315        }
    201316        // Unix timestamps after 03:14:07 UTC 2038-01-19 might cause an overflow
    202317        // if 32 bit integers are used.
    203         $timestamp = mktime((int)$date[4],
    204                             (int)$date[5],
    205                             (int)$date[6],
    206                             (int)$date[2],
    207                             (int)$date[3],
    208                             (int)$date[1]);
    209         return  $timestamp;
    210     }
     318        $timestamp = mktime((int)$date[4], (int)$date[5], (int)$date[6], (int)$date[2], (int)$date[3], (int)$date[1]);
     319        return $timestamp;
     320    }
     321
     322    /**
     323     * Processes recurrences
     324     *
     325     * @author John Grogg <john.grogg@gmail.com>
     326     * @return {array}
     327     */
     328    public function process_recurrences()
     329    {
     330        $array = $this->cal;
     331        $events = $array['VEVENT'];
     332        if (empty($events))
     333            return false;
     334        foreach ($array['VEVENT'] as $anEvent) {
     335            if (isset($anEvent['RRULE']) && $anEvent['RRULE'] != '') {
     336                // Recurring event, parse RRULE and add appropriate duplicate events
     337                $rrules = array();
     338                $rrule_strings = explode(';', $anEvent['RRULE']);
     339                foreach ($rrule_strings as $s) {
     340                    list($k, $v) = explode('=', $s);
     341                    $rrules[$k] = $v;
     342                }
     343                // Get frequency
     344                $frequency = $rrules['FREQ'];
     345                // Get Start timestamp
     346                $start_timestamp = $this->iCalDateToUnixTimestamp($anEvent['DTSTART']);
     347                $end_timestamp = $this->iCalDateToUnixTimestamp($anEvent['DTEND']);
     348                $event_timestamp_offset = $end_timestamp - $start_timestamp;
     349                // Get Interval
     350                $interval = (isset($rrules['INTERVAL']) && $rrules['INTERVAL'] != '') ? $rrules['INTERVAL'] : 1;
     351
     352                if (in_array($frequency, array('MONTHLY', 'YEARLY')) && isset($rrules['BYDAY']) && $rrules['BYDAY'] != '') {
     353                    // Deal with BYDAY
     354                    $day_number = intval($rrules['BYDAY']);
     355                    if (empty($day_number)) { // Returns 0 when no number defined in BYDAY
     356                        if (!isset($rrules['BYSETPOS'])) {
     357                            $day_number = 1; // Set first as default
     358                        } else if (is_numeric($rrules['BYSETPOS'])) {
     359                            $day_number = $rrules['BYSETPOS'];
     360                        }
     361                    }
     362                    $day_number = ($day_number == -1) ? 6 : $day_number; // Override for our custom key (6 => 'last')
     363                    $week_day = substr($rrules['BYDAY'], -2);
     364                    $day_ordinals = array(1 => 'first', 2 => 'second', 3 => 'third', 4 => 'fourth', 5 => 'fifth', 6 => 'last');
     365                    $weekdays = array('SU' => 'sunday', 'MO' => 'monday', 'TU' => 'tuesday', 'WE' => 'wednesday', 'TH' => 'thursday', 'FR' => 'friday', 'SA' => 'saturday');
     366                }
     367
     368                $until_default = date_create('now');
     369                $until_default->modify($this->default_span . ' year');
     370                $until_default->setTime(23, 59, 59); // End of the day
     371                $until_default = date_format($until_default, 'Ymd\THis');
     372
     373                if (isset($rrules['UNTIL'])) {
     374                    // Get Until
     375                    $until = $this->iCalDateToUnixTimestamp($rrules['UNTIL']);
     376                } else if (isset($rrules['COUNT'])) {
     377                    $frequency_conversion = array('DAILY' => 'day', 'WEEKLY' => 'week', 'MONTHLY' => 'month', 'YEARLY' => 'year');
     378                    $count_orig = (is_numeric($rrules['COUNT']) && $rrules['COUNT'] > 1) ? $rrules['COUNT'] : 0;
     379                    $count = ($count_orig - 1); // Remove one to exclude the occurrence that initialises the rule
     380                    $count += ($count > 0) ? $count * ($interval - 1) : 0;
     381                    $offset = "+$count " . $frequency_conversion[$frequency];
     382                    $until = strtotime($offset, $start_timestamp);
     383
     384                    if (in_array($frequency, array('MONTHLY', 'YEARLY')) && isset($rrules['BYDAY']) && $rrules['BYDAY'] != '') {
     385                        $dtstart = date_create($anEvent['DTSTART']);
     386                        for ($i = 1; $i <= $count; $i++) {
     387                            $dtstart_clone = clone $dtstart;
     388                            $dtstart_clone->modify('next ' . $frequency_conversion[$frequency]);
     389                            $offset = "{$day_ordinals[$day_number]} {$weekdays[$week_day]} of " . $dtstart_clone->format('F Y H:i:01');
     390                            $dtstart->modify($offset);
     391                        }
     392
     393                        // Jumping X months forwards doesn't mean the end date will fall on the same day defined in BYDAY
     394                        // Use the largest of these to ensure we are going far enough in the future to capture our final end day
     395                        $until = max($until, $dtstart->format('U'));
     396                    }
     397
     398                    unset($offset);
     399                } else {
     400                    $until = $this->iCalDateToUnixTimestamp($until_default);
     401                }
     402
     403                if(!isset($anEvent['EXDATE_array'])){
     404                    $anEvent['EXDATE_array'] = array();
     405                }
     406
     407                // Decide how often to add events and do so
     408                switch ($frequency) {
     409                    case 'DAILY':
     410                        // Simply add a new event each interval of days until UNTIL is reached
     411                        $offset = "+$interval day";
     412                        $recurring_timestamp = strtotime($offset, $start_timestamp);
     413
     414                        while ($recurring_timestamp <= $until) {
     415                            // Add event
     416                            $anEvent['DTSTART'] = date('Ymd\THis', $recurring_timestamp);
     417                            $anEvent['DTEND'] = date('Ymd\THis', $recurring_timestamp + $event_timestamp_offset);
     418
     419                            $search_date = $anEvent['DTSTART'];
     420                            $is_excluded = array_filter($anEvent['EXDATE_array'], function($val) use ($search_date) {
     421                                return is_string($val) && strpos($search_date, $val) === 0;
     422                            });
     423
     424                            if (!$is_excluded) {
     425                                $events[] = $anEvent;
     426                            }
     427
     428                            // Move forwards
     429                            $recurring_timestamp = strtotime($offset, $recurring_timestamp);
     430                        }
     431                        break;
     432                    case 'WEEKLY':
     433                        // Create offset
     434                        $offset = "+$interval week";
     435                        // Build list of days of week to add events
     436                        $weekdays = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
     437
     438                        if (isset($rrules['BYDAY']) && $rrules['BYDAY'] != '') {
     439                            $bydays = explode(',', $rrules['BYDAY']);
     440                        } else {
     441                            $weekTemp = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
     442                            $findDay = $weekTemp[date('w', $start_timestamp)];
     443                            $bydays = array($findDay);
     444                        }
     445
     446                        // Get timestamp of first day of start week
     447                        $week_recurring_timestamp = (date('w', $start_timestamp) == 0) ? $start_timestamp : strtotime('last Sunday ' . date('H:i:s', $start_timestamp), $start_timestamp);
     448
     449                        // Step through weeks
     450                        while ($week_recurring_timestamp <= $until) {
     451                            // Add events for bydays
     452                            $day_recurring_timestamp = $week_recurring_timestamp;
     453
     454                            foreach ($weekdays as $day) {
     455                                // Check if day should be added
     456
     457                                if (in_array($day, $bydays) && $day_recurring_timestamp > $start_timestamp && $day_recurring_timestamp <= $until) {
     458                                    // Add event to day
     459                                    $anEvent['DTSTART'] = date('Ymd\THis', $day_recurring_timestamp);
     460                                    $anEvent['DTEND'] = date('Ymd\THis', $day_recurring_timestamp + $event_timestamp_offset);
     461
     462                                    $search_date = $anEvent['DTSTART'];
     463                                    $is_excluded = array_filter($anEvent['EXDATE_array'], function($val) use ($search_date) { return is_string($val) && strpos($search_date, $val) === 0; });
     464
     465                                    if (!$is_excluded) {
     466                                        $events[] = $anEvent;
     467                                    }
     468                                }
     469
     470                                // Move forwards a day
     471                                $day_recurring_timestamp = strtotime('+1 day', $day_recurring_timestamp);
     472                            }
     473
     474                            // Move forwards $interval weeks
     475                            $week_recurring_timestamp = strtotime($offset, $week_recurring_timestamp);
     476                        }
     477                        break;
     478                    case 'MONTHLY':
     479                        // Create offset
     480                        $offset = "+$interval month";
     481                        $recurring_timestamp = strtotime($offset, $start_timestamp);
     482
     483                        if (isset($rrules['BYMONTHDAY']) && $rrules['BYMONTHDAY'] != '') {
     484                            // Deal with BYMONTHDAY
     485                            $monthdays = explode(',', $rrules['BYMONTHDAY']);
     486
     487                            while ($recurring_timestamp <= $until) {
     488                                foreach ($monthdays as $monthday) {
     489                                    // Add event
     490                                    $anEvent['DTSTART'] = date('Ym' . sprintf('%02d', $monthday) . '\THis', $recurring_timestamp);
     491                                    $anEvent['DTEND'] = date('Ymd\THis', $this->iCalDateToUnixTimestamp($anEvent['DTSTART']) + $event_timestamp_offset);
     492
     493                                    $search_date = $anEvent['DTSTART'];
     494                                    $is_excluded = array_filter($anEvent['EXDATE_array'], function($val) use ($search_date) { return is_string($val) && strpos($search_date, $val) === 0; });
     495
     496                                    if (!$is_excluded) {
     497                                        $events[] = $anEvent;
     498                                    }
     499                                }
     500
     501                                // Move forwards
     502                                $recurring_timestamp = strtotime($offset, $recurring_timestamp);
     503                            }
     504                        } else if (isset($rrules['BYDAY']) && $rrules['BYDAY'] != '') {
     505                            $start_time = date('His', $start_timestamp);
     506
     507                            while ($recurring_timestamp <= $until) {
     508                                $event_start_desc = "{$day_ordinals[$day_number]} {$weekdays[$week_day]} of " . date('F Y H:i:s', $recurring_timestamp);
     509                                $event_start_timestamp = strtotime($event_start_desc);
     510
     511                                if ($event_start_timestamp > $start_timestamp && $event_start_timestamp < $until) {
     512                                    $anEvent['DTSTART'] = date('Ymd\T', $event_start_timestamp) . $start_time;
     513                                    $anEvent['DTEND'] = date('Ymd\THis', $this->iCalDateToUnixTimestamp($anEvent['DTSTART']) + $event_timestamp_offset);
     514
     515                                    $search_date = $anEvent['DTSTART'];
     516                                    $is_excluded = array_filter($anEvent['EXDATE_array'], function($val) use ($search_date) { return is_string($val) && strpos($search_date, $val) === 0; });
     517
     518                                    if (!$is_excluded) {
     519                                        $events[] = $anEvent;
     520                                    }
     521                                }
     522
     523                                // Move forwards
     524                                $recurring_timestamp = strtotime($offset, $recurring_timestamp);
     525                            }
     526                        }
     527                        break;
     528                    case 'YEARLY':
     529                        // Create offset
     530                        $offset = "+$interval year";
     531                        $recurring_timestamp = strtotime($offset, $start_timestamp);
     532                        $month_names = array(1 => 'January', 2 => 'February', 3 => 'March', 4 => 'April', 5 => 'May', 6 => 'June', 7 => 'July', 8 => 'August', 9 => 'September', 10 => 'October', 11 => 'November', 12 => 'December');
     533
     534                        // Check if BYDAY rule exists
     535                        if (isset($rrules['BYDAY']) && $rrules['BYDAY'] != '') {
     536                            $start_time = date('His', $start_timestamp);
     537
     538                            while ($recurring_timestamp <= $until) {
     539                                $event_start_desc = "{$day_ordinals[$day_number]} {$weekdays[$week_day]} of {$month_names[$rrules['BYMONTH']]} " . date('Y H:i:s', $recurring_timestamp);
     540                                $event_start_timestamp = strtotime($event_start_desc);
     541
     542                                if ($event_start_timestamp > $start_timestamp && $event_start_timestamp < $until) {
     543                                    $anEvent['DTSTART'] = date('Ymd\T', $event_start_timestamp) . $start_time;
     544                                    $anEvent['DTEND'] = date('Ymd\THis', $this->iCalDateToUnixTimestamp($anEvent['DTSTART']) + $event_timestamp_offset);
     545
     546                                    $search_date = $anEvent['DTSTART'];
     547                                    $is_excluded = array_filter($anEvent['EXDATE_array'], function($val) use ($search_date) { return is_string($val) && strpos($search_date, $val) === 0; });
     548
     549                                    if (!$is_excluded) {
     550                                        $events[] = $anEvent;
     551                                    }
     552                                }
     553
     554                                // Move forwards
     555                                $recurring_timestamp = strtotime($offset, $recurring_timestamp);
     556                            }
     557                        } else {
     558                            $day = date('d', $start_timestamp);
     559                            $start_time = date('His', $start_timestamp);
     560
     561                            // Step through years
     562                            while ($recurring_timestamp <= $until) {
     563                                // Add specific month dates
     564                                if (isset($rrules['BYMONTH']) && $rrules['BYMONTH'] != '') {
     565                                    $event_start_desc = "$day {$month_names[$rrules['BYMONTH']]} " . date('Y H:i:s', $recurring_timestamp);
     566                                } else {
     567                                    $event_start_desc = $day . date('F Y H:i:s', $recurring_timestamp);
     568                                }
     569
     570                                $event_start_timestamp = strtotime($event_start_desc);
     571
     572                                if ($event_start_timestamp > $start_timestamp && $event_start_timestamp < $until) {
     573                                    $anEvent['DTSTART'] = date('Ymd\T', $event_start_timestamp) . $start_time;
     574                                    $anEvent['DTEND'] = date('Ymd\THis', $this->iCalDateToUnixTimestamp($anEvent['DTSTART']) + $event_timestamp_offset);
     575
     576                                    $search_date = $anEvent['DTSTART'];
     577                                    $is_excluded = array_filter($anEvent['EXDATE_array'], function($val) use ($search_date) { return is_string($val) && strpos($search_date, $val) === 0; });
     578
     579                                    if (!$is_excluded) {
     580                                        $events[] = $anEvent;
     581                                    }
     582                                }
     583
     584                                // Move forwards
     585                                $recurring_timestamp = strtotime($offset, $recurring_timestamp);
     586                            }
     587                        }
     588                        break;
     589
     590                    $events = (isset($count_orig) && sizeof($events) > $count_orig) ? array_slice($events, 0, $count_orig) : $events; // Ensure we abide by COUNT if defined
     591                }
     592            }
     593        }
     594        $this->cal['VEVENT'] = $events;
     595    }
    211596
    212597    /**
     
    216601     * @return {array}
    217602     */
    218     public function events() 
     603    public function events()
    219604    {
    220605        $array = $this->cal;
    221         if(isset($array['VEVENT']))
    222             return $array['VEVENT'];
    223         return false;
    224     }
    225 
    226     /**
    227      * Returns a boolean value whether thr current calendar has events or not
     606        return $array['VEVENT'];
     607    }
     608
     609    /**
     610     * Returns the calendar name
     611     *
     612     * @return {calendar name}
     613     */
     614    public function calendarName()
     615    {
     616        return $this->cal['VCALENDAR']['X-WR-CALNAME'];
     617    }
     618
     619    /**
     620     * Returns the calendar description
     621     *
     622     * @return {calendar description}
     623     */
     624    public function calendarDescription()
     625    {
     626        return $this->cal['VCALENDAR']['X-WR-CALDESC'];
     627    }
     628
     629    /**
     630     * Returns an array of arrays with all free/busy events. Every event is
     631     * an associative array and each property is an element it.
     632     *
     633     * @return {array}
     634     */
     635    public function freeBusyEvents()
     636    {
     637        $array = $this->cal;
     638        return $array['VFREEBUSY'];
     639    }
     640
     641    /**
     642     * Returns a boolean value whether the current calendar has events or not
    228643     *
    229644     * @return {boolean}
    230645     */
    231     public function hasEvents() 
    232     {
    233         return ( count($this->events()) > 0 ? true : false );
     646    public function hasEvents()
     647    {
     648        return (count($this->events()) > 0) ? true : false;
    234649    }
    235650
     
    237652     * Returns false when the current calendar has no events in range, else the
    238653     * events.
    239      * 
    240      * Note that this function makes use of a UNIX timestamp. This might be a 
     654     *
     655     * Note that this function makes use of a UNIX timestamp. This might be a
    241656     * problem on January the 29th, 2038.
    242657     * See http://en.wikipedia.org/wiki/Unix_time#Representing_the_number
     
    247662     * @return {mixed}
    248663     */
    249     public function eventsFromRange($rangeStart = false, $rangeEnd = false) 
     664    public function eventsFromRange($rangeStart = false, $rangeEnd = false)
    250665    {
    251666        $events = $this->sortEventsWithOrder($this->events(), SORT_ASC);
     
    256671
    257672        $extendedEvents = array();
    258        
    259         if ($rangeStart !== false) {
     673
     674        if ($rangeStart === false) {
    260675            $rangeStart = new DateTime();
    261         }
    262 
    263         if ($rangeEnd !== false or $rangeEnd <= 0) {
     676        } else {
     677            $rangeStart = new DateTime($rangeStart);
     678        }
     679
     680        if ($rangeEnd === false or $rangeEnd <= 0) {
    264681            $rangeEnd = new DateTime('2038/01/18');
    265682        } else {
     
    270687        $rangeEnd   = $rangeEnd->format('U');
    271688
    272        
    273 
    274         // loop through all events by adding two new elements
     689        // Loop through all events by adding two new elements
    275690        foreach ($events as $anEvent) {
    276691            $timestamp = $this->iCalDateToUnixTimestamp($anEvent['DTSTART']);
     
    284699
    285700    /**
    286      * Returns a boolean value whether thr current calendar has events or not
     701     * Returns a boolean value whether the current calendar has events or not
    287702     *
    288703     * @param {array} $events    An array with events.
    289      * @param {array} $sortOrder Either SORT_ASC, SORT_DESC, SORT_REGULAR, 
     704     * @param {array} $sortOrder Either SORT_ASC, SORT_DESC, SORT_REGULAR,
    290705     *                           SORT_NUMERIC, SORT_STRING
    291706     *
     
    295710    {
    296711        $extendedEvents = array();
    297        
    298         // loop through all events by adding two new elements
     712
     713        // Loop through all events by adding two new elements
    299714        foreach ($events as $anEvent) {
    300715            if (!array_key_exists('UNIX_TIMESTAMP', $anEvent)) {
    301                 $anEvent['UNIX_TIMESTAMP'] =
    302                             $this->iCalDateToUnixTimestamp($anEvent['DTSTART']);
     716                $anEvent['UNIX_TIMESTAMP'] = $this->iCalDateToUnixTimestamp($anEvent['DTSTART']);
    303717            }
    304718
    305719            if (!array_key_exists('REAL_DATETIME', $anEvent)) {
    306                 $anEvent['REAL_DATETIME'] =
    307                             date("d.m.Y", $anEvent['UNIX_TIMESTAMP']);
     720                $anEvent['REAL_DATETIME'] = date('d.m.Y', $anEvent['UNIX_TIMESTAMP']);
    308721            }
    309            
     722
    310723            $extendedEvents[] = $anEvent;
    311724        }
    312        
     725
    313726        foreach ($extendedEvents as $key => $value) {
    314727            $timestamp[$key] = $value['UNIX_TIMESTAMP'];
     
    318731        return $extendedEvents;
    319732    }
    320 }
    321 ?>
     733}
  • wp-ical-availability/trunk/include/pluginShortcode.php

    r1363945 r1370585  
    4545        $calendarOptions =(!empty($calendar['calendarOptions'])) ? json_decode($calendar['calendarOptions'],true) : false;
    4646       
    47         $calendarOutput .= wpia_calendar(array('ajaxCall' => false, 'calendarID' => $calendar['calendarID'], 'calendarFeed' => $calendarOptions['icalendar_feed'], 'showDateEditor' => false, 'calendarLanguage' => $language ));
     47        $calendarOutput .= wpia_calendar(array('ajaxCall' => false, 'calendarID' => $calendar['calendarID'], 'calendarFeed' => $calendarOptions['icalendar_feed'][0], 'showDateEditor' => false, 'calendarLanguage' => $language ));
    4848       
    4949
  • wp-ical-availability/trunk/readme.txt

    r1366824 r1370585  
    44Requires at least: 3.0
    55Tested up to: 4.4.2
    6 Stable tag: 0.2
     6Stable tag: 0.3
    77
    88This calendar imports an iCal feed from an external website, like Airbnb, and shows the availability based on that feed.
     
    6767== Changelog ==
    6868
     69= 0.3 =
     70* Updated ics parser class
     71* Fixed a compatibility issue with the premium version
     72
    6973= 0.2 =
    7074* Fixed importing URLs with special characters or blank spaces
     
    7579== Upgrade Notice ==
    7680
     81= 0.3 =
     82* Updated ics parser class
     83* Fixed a compatibility issue with the premium version
     84
    7785= 0.2 =
    7886* Fixed importing URLs with special characters or blank spaces
  • wp-ical-availability/trunk/views/calendar/edit-calendar.php

    r1363945 r1370585  
    4141                            <?php $calendarOptions =(!empty($calendar['calendarOptions'])) ? json_decode($calendar['calendarOptions'],true) : false;?>
    4242                            <?php if(empty($wpiaOptions['backendStartDay'])) $wpiaOptions['backendStartDay'] = 1;?>
    43                            
     43                            <?php if(!is_array($calendarOptions['icalendar_feed'])) { $feed = $calendarOptions['icalendar_feed']; unset($calendarOptions['icalendar_feed']); $calendarOptions['icalendar_feed'][0] = $feed;} ?>
    4444                           
    4545                                             
    46                             <?php echo wpia_calendar( array( 'calendarFeed' => $calendarOptions['icalendar_feed'], 'calendarID' => (!empty($calendar['calendarID'])) ? $calendar['calendarID'] : "", 'firstDayOfWeek' => $wpiaOptions['backendStartDay'], 'showDateEditor' =>  true ) );?>
     46                            <?php echo wpia_calendar( array( 'calendarFeed' => $calendarOptions['icalendar_feed'][0], 'calendarID' => (!empty($calendar['calendarID'])) ? $calendar['calendarID'] : "", 'firstDayOfWeek' => $wpiaOptions['backendStartDay'], 'showDateEditor' =>  true ) );?>
    4747                            <input type="hidden" value="<?php echo (!empty($calendar['calendarID'])) ? $calendar['calendarID'] : "" ;?>" name="calendarID" />   
    4848                           
     
    6161                                <tr>
    6262                                    <th scope="row"><label for="icalendar_feed"><?php _e('iCalendar Feed','wpia');?></label></th>
    63                                     <td><input name="icalendar_feed" type="text" id="icalendar_feed" value="<?php echo (!empty($calendarOptions['icalendar_feed'])) ? esc_url($calendarOptions['icalendar_feed']) : '';?>" class="widefat" />
    64                                     <?php if(!empty($calendarOptions['icalendar_feed'])): $ical = new ICal($calendarOptions['icalendar_feed']); if(isset($ical->cal) == false): ?>
     63                                    <td><input name="icalendar_feed" type="text" id="icalendar_feed" value="<?php echo (!empty($calendarOptions['icalendar_feed'][0])) ? esc_url($calendarOptions['icalendar_feed'][0]) : '';?>" class="widefat" />
     64                                    <?php if(!empty($calendarOptions['icalendar_feed'][0])): $ical = new ICal($calendarOptions['icalendar_feed'][0]); if(isset($ical->cal) == false): ?>
    6565                   
    6666                                    <small style="color:red;"><?php _e('Invalid iCalendar Feed','wpia');?></small>
  • wp-ical-availability/trunk/wp-ical-availability.php

    r1366824 r1370585  
    44 * Plugin URI:  http://www.wpicalavailability.com
    55 * Description: WP iCal Availability
    6  * Version:     0.2
     6 * Version:     0.3
    77 * Author:      WP iCal Availability
    88 * Author URI:  http://www.wpicalavailability.com
Note: See TracChangeset for help on using the changeset viewer.