Esempio n. 1
0
 /**
  * function iCal2xls
  *
  * Convert iCal file to xls format and send file to browser (default) or save xls file to disk
  * Definition iCal  : rcf2445, http://kigkonsult.se/downloads/index.php#rfc
  * Using iCalcreator: http://kigkonsult.se/downloads/index.php#iCalcreator
  * Based on PEAR Spreadsheet_Excel_Writer-0.9.1 (and OLE-1.0.0RC1)
  * to be installed as
  * pear install channel://pear.php.net/OLE-1.0.0RC1
  * pear install channel://pear.php.net/Spreadsheet_Excel_Writer-0.9.1
  *
  * @author Kjell-Inge Gustafsson <*****@*****.**>
  * @since  3.0 - 2011-12-21
  * @param  object $calendar opt. iCalcreator calendar instance
  * @return bool   returns FALSE when error
  */
 public function iCal2xls($calendar = FALSE)
 {
     $timeexec = array('start' => microtime(TRUE));
     if ($this->log) {
         $this->log->log(' ********** START **********', PEAR_LOG_NOTICE);
     }
     /** check input/output directory and filename */
     $inputdirFile = $outputdirFile = '';
     $inputFileParts = $outputFileParts = array();
     $remoteInput = $remoteOutput = FALSE;
     if ($calendar) {
         $inputdirFile = $calendar->getConfig('DIRFILE');
         $inputFileParts = pathinfo($inputdirFile);
         $inputFileParts['dirname'] = realpath($inputFileParts['dirname']);
         if ($this->log) {
             $this->log->log('fileParts:' . var_export($inputFileParts, TRUE), PEAR_LOG_DEBUG);
         }
     } elseif (FALSE === $this->_fixIO('input', 'ics', $inputdirFile, $inputFileParts, $remoteInput)) {
         if ($this->log) {
             $this->log->log(number_format(microtime(TRUE) - $timeexec['start'], 5) . ' sec', PEAR_LOG_ERR);
             $this->log->log("ERROR 2, invalid input ({$inputdirFile})", PEAR_LOG_ERR);
             $this->log->flush();
         }
         return FALSE;
     }
     if (FALSE === $this->_fixIO('output', FALSE, $outputdirFile, $outputFileParts, $remoteOutput)) {
         if (FALSE === $this->setConfig('outputfilename', $inputFileParts['filename'] . '.xls')) {
             if ($this->log) {
                 $this->log->log(number_format(microtime(TRUE) - $timeexec['start'], 5) . ' sec', PEAR_LOG_ERR);
                 $this->log->log('ERROR 3, invalid output (' . $inputFileParts['filename'] . '.csv)', PEAR_LOG_ERR);
                 $this->log->flush();
             }
             return FALSE;
         }
         $outputdirFile = $this->getConfig('outputdirectory') . DIRECTORY_SEPARATOR . $inputFileParts['filename'] . '.xls';
         $outputFileParts = pathinfo($outputdirFile);
         if ($this->log) {
             $this->log->log("output set to '{$outputdirFile}'", PEAR_LOG_INFO);
         }
     }
     if ($this->log) {
         $this->log->log("INPUT..FILE:{$inputdirFile}", PEAR_LOG_NOTICE);
         $this->log->log("OUTPUT.FILE:{$outputdirFile}", PEAR_LOG_NOTICE);
     }
     $save = $this->getConfig('save');
     if ($calendar) {
         $calnl = $calendar->getConfig('nl');
     } else {
         /** iCalcreator set config, read and parse input iCal file */
         $calendar = new vcalendar();
         if (FALSE !== ($unique_id = $this->getConfig('unique_id'))) {
             $calendar->setConfig('unique_id', $unique_id);
         }
         $calnl = $calendar->getConfig('nl');
         if ($remoteInput) {
             if (FALSE === $calendar->setConfig('url', $inputdirFile)) {
                 if ($this->log) {
                     $this->log->log("ERROR 3 INPUT FILE:'{$inputdirFile}' iCalcreator: invalid url", 3);
                 }
                 return FALSE;
             }
         } else {
             if (FALSE === $calendar->setConfig('directory', $inputFileParts['dirname'])) {
                 if ($this->log) {
                     $this->log->log("ERROR 4 INPUT FILE:'{$inputdirFile}' iCalcreator: invalid directory: '" . $inputFileParts['dirname'] . "'", 3);
                     $this->log->flush();
                 }
                 return FALSE;
             }
             if (FALSE === $calendar->setConfig('filename', $inputFileParts['basename'])) {
                 if ($this->log) {
                     $this->log->log("ERROR 5 INPUT FILE:'{$inputdirFile}' iCalcreator: invalid filename: '" . $inputFileParts['basename'] . "'", 3);
                     $this->log->flush();
                 }
                 return FALSE;
             }
         }
         if (FALSE === $calendar->parse()) {
             if ($this->log) {
                 $this->log->log("ERROR 6 INPUT FILE:'{$inputdirFile}' iCalcreator parse error", 3);
                 $this->log->flush();
             }
             return FALSE;
         }
     }
     // end if( !$calendar )
     $timeexec['fileOk'] = microtime(TRUE);
     if (!function_exists('iCaldate2timestamp')) {
         function iCaldate2timestamp($d)
         {
             if (6 > count($d)) {
                 return mktime(0, 0, 0, $d['month'], $d['day'], $d['year']);
             } else {
                 return mktime($d['hour'], $d['min'], $d['sec'], $d['month'], $d['day'], $d['year']);
             }
         }
     }
     if (!function_exists('fixiCalString')) {
         function fixiCalString($s)
         {
             global $calnl;
             $s = str_replace('\\,', ',', $s);
             $s = str_replace('\\;', ';', $s);
             $s = str_replace('\\n ', chr(10), $s);
             $s = str_replace('\\\\', '\\', $s);
             $s = str_replace("{$calnl}", chr(10), $s);
             return utf8_decode($s);
         }
     }
     /** Creating a workbook */
     require_once 'Spreadsheet/Excel/Writer.php';
     if ($save) {
         $workbook = new Spreadsheet_Excel_Writer($outputdirFile);
     } else {
         $workbook = new Spreadsheet_Excel_Writer();
     }
     $workbook->setVersion(8);
     // Use Excel97/2000 Format
     /** opt. sending HTTP headers */
     if (!$save) {
         $workbook->send($outputFileParts['basename']);
     }
     /** Creating a worksheet */
     $worksheet =& $workbook->addWorksheet($inputFileParts['filename']);
     /** fix formats */
     $format_bold =& $workbook->addFormat();
     $format_bold->setBold();
     $timeexec['wrkbkOk'] = microtime(TRUE);
     /** info rows */
     $row = -1;
     $worksheet->writeString(++$row, 0, 'kigkonsult.se', $format_bold);
     $worksheet->writeString($row, 1, ICALCREATOR_VERSION, $format_bold);
     $worksheet->writeString($row, 2, ICALCNVVERSION . ' iCal2xls', $format_bold);
     $worksheet->writeString($row, 3, date('Y-m-d H:i:s'));
     $filename = $remoteInput ? $inputdirFile : $inputFileParts['basename'];
     $worksheet->writeString(++$row, 0, 'iCal input', $format_bold);
     $worksheet->writeString($row, 1, $filename);
     $worksheet->writeString($row, 2, 'xls output', $format_bold);
     $worksheet->writeString($row, 3, $outputFileParts['basename']);
     if (FALSE !== ($prop = $calendar->getProperty('CALSCALE'))) {
         $worksheet->writeString(++$row, 0, 'CALSCALE', $format_bold);
         $worksheet->writeString($row, 1, $prop);
     }
     if (FALSE !== ($prop = $calendar->getProperty('METHOD'))) {
         $worksheet->writeString(++$row, 0, 'METHOD', $format_bold);
         $worksheet->writeString($row, 1, $prop);
     }
     while (FALSE !== ($xprop = $calendar->getProperty())) {
         $worksheet->writeString(++$row, 0, $xprop[0], $format_bold);
         $worksheet->writeString($row, 1, $xprop[1]);
     }
     $timeexec['infoOk'] = microtime(TRUE);
     if (FALSE === ($propsToSkip = $this->getConfig('skip'))) {
         $propsToSkip = array();
     }
     /** fix property order list */
     $proporderOrg = array();
     for ($key = 2; $key < 99; $key++) {
         if (FALSE !== ($value = $this->getConfig($key))) {
             $proporderOrg[$value] = $key;
             if ($this->log) {
                 $this->log->log("{$value} in column {$key}", 7);
             }
         }
     }
     /** fix vtimezone property order list */
     $proporder = $proporderOrg;
     $proporder['TYPE'] = 0;
     $proporder['ORDER'] = 1;
     $props = array('TZID', 'LAST-MODIFIED', 'TZURL', 'DTSTART', 'TZOFFSETTO', 'TZOFFSETFROM', 'COMMENT', 'RRULE', 'RDATE', 'TZNAME');
     $pix = 2;
     foreach ($props as $prop) {
         if (isset($proporder[$prop])) {
             continue;
         }
         if (in_array($prop, $propsToSkip)) {
             if ($this->log) {
                 $this->log->log("'{$prop}' removed from output", 7);
             }
             continue;
         }
         while (in_array($pix, $proporder)) {
             $pix++;
         }
         $proporder[$prop] = $pix++;
     }
     /** remove unused properties from and add x-props to property order list */
     $maxpropix = 11;
     if ($maxpropix != count($proporder) - 1) {
         $maxpropix = count($proporder) - 1;
     }
     $compsinfo = $calendar->getConfig('compsinfo');
     $potmp = array();
     $potmp[0] = 'TYPE';
     $potmp[1] = 'ORDER';
     foreach ($compsinfo as $cix => $compinfo) {
         if ('vtimezone' != $compinfo['type']) {
             continue;
         }
         $comp = $calendar->getComponent($compinfo['ordno']);
         foreach ($compinfo['props'] as $propName => $propcnt) {
             if (!in_array($propName, $potmp) && isset($proporder[$propName])) {
                 $potmp[$proporder[$propName]] = $propName;
             } elseif ('X-PROP' == $propName) {
                 while ($xprop = $comp->getProperty()) {
                     if (!in_array($xprop[0], $potmp)) {
                         $maxpropix += 1;
                         $potmp[$maxpropix] = $xprop[0];
                     }
                     // end if
                 }
                 // end while xprop
             }
             // end X-PROP
         }
         // end $compinfo['props']
         if (isset($compinfo['sub'])) {
             foreach ($compinfo['sub'] as $compinfo2) {
                 foreach ($compinfo2['props'] as $propName => $propcnt) {
                     if (!in_array($propName, $potmp) && isset($proporder[$propName])) {
                         $potmp[$proporder[$propName]] = $propName;
                     } elseif ('X-PROP' == $propName) {
                         $scomp = $comp->getComponent($compinfo2['ordno']);
                         while ($xprop = $scomp->getProperty()) {
                             if (!in_array($xprop[0], $potmp)) {
                                 $maxpropix += 1;
                                 $potmp[$maxpropix] = $xprop[0];
                             }
                             // end if
                         }
                         // end while xprop
                     }
                     // end X-PROP
                 }
                 // end $compinfo['sub']['props']
             }
             // end foreach( $compinfo['sub']
         }
         // end if( isset( $compinfo['sub']
     }
     // end foreach compinfo - vtimezone
     ksort($potmp, SORT_NUMERIC);
     $proporder = array_flip(array_values($potmp));
     if ($this->log) {
         $this->log->log("timezone proporder=" . implode(',', array_flip($proporder)), 7);
     }
     /** create vtimezone info */
     if (2 < count($proporder)) {
         $row += 1;
         /** create vtimezone header row */
         foreach ($proporder as $propName => $col) {
             if (isset($this->config[$propName])) {
                 $worksheet->writeString($row, $col, $this->config[$propName], $format_bold);
                 // check map of userfriendly name to iCal property name
                 if ($this->log) {
                     $this->log->log("header row, col={$col}: {$propName}, replaced by " . $this->config[$propName], 7);
                 }
             } else {
                 $worksheet->writeString($row, $col, $propName, $format_bold);
             }
         }
         $allowedProps = array('VTIMEZONE' => array('TZID', 'LAST-MODIFIED', 'TZURL'), 'STANDARD' => array('DTSTART', 'TZOFFSETTO', 'TZOFFSETFROM', 'COMMENT', 'RDATE', 'RRULE', 'TZNAME'), 'DAYLIGHT' => array('DTSTART', 'TZOFFSETTO', 'TZOFFSETFROM', 'COMMENT', 'RDATE', 'RRULE', 'TZNAME'));
         /** create vtimezone data rows */
         foreach ($compsinfo as $cix => $compinfo) {
             if ('vtimezone' != $compinfo['type']) {
                 continue;
             }
             $row += 1;
             $worksheet->writeString($row, $proporder['TYPE'], $compinfo['type']);
             $worksheet->writeString($row, $proporder['ORDER'], $compinfo['ordno']);
             $comp = $calendar->getComponent($compinfo['ordno']);
             foreach ($proporder as $propName => $col) {
                 if ('TYPE' == $propName || 'ORDER' == $propName) {
                     continue;
                 }
                 if ('X-' == substr($propName, 0, 2)) {
                     continue;
                 }
                 if (!in_array($propName, $allowedProps['VTIMEZONE'])) {
                     // check if component allows property
                     if ($this->log) {
                         $this->log->log("ERROR 7, INPUT FILE:'{$inputdirFile}' iCalcreator: unvalid property for component '" . $compinfo['type'] . "': '{$propName}'", PEAR_LOG_INFO);
                     }
                     continue;
                 }
                 if (isset($compinfo['props'][$propName])) {
                     if ('LAST-MODIFIED' == $propName) {
                         $fcn = 'createLastModified';
                     } else {
                         $fcn = 'create' . strtoupper(substr($propName, 0, 1)) . strtolower(substr($propName, 1));
                     }
                     if (!method_exists($comp, $fcn)) {
                         if ($this->log) {
                             $this->log->log('ERROR 8 INPUT FILE:"' . $filename . '" iCalcreator: unknown property: "' . $propName . '" (' . $fcn . ')', PEAR_LOG_INFO);
                         }
                         continue;
                     }
                     $output = str_replace("{$calnl} ", '', rtrim($comp->{$fcn}()));
                     $output = str_replace($propName . ';', '', $output);
                     $output = str_replace($propName . ':', '', $output);
                     $worksheet->writeString($row, $proporder[$propName], fixiCalString($output));
                 }
             }
             // end foreach( $proporder
             if (isset($compinfo['props']['X-PROP'])) {
                 while ($xprop = $comp->getProperty()) {
                     $output = str_replace("{$calnl} ", '', rtrim($xprop[1]));
                     $worksheet->writeString($row, $proporder[$xprop[0]], fixiCalString($output));
                 }
             }
             if (isset($compinfo['sub'])) {
                 foreach ($compinfo['sub'] as $compinfo2) {
                     $row += 1;
                     $worksheet->writeString($row, $proporder['TYPE'], $compinfo2['type']);
                     $worksheet->writeString($row, $proporder['ORDER'], $compinfo['ordno'] . ':' . $compinfo2['ordno']);
                     $scomp = $comp->getComponent($compinfo2['ordno']);
                     foreach ($proporder as $propName => $col) {
                         if ('TYPE' == $propName || 'ORDER' == $propName) {
                             continue;
                         }
                         if ('X-' == substr($propName, 0, 2)) {
                             continue;
                         }
                         if (!in_array($propName, $allowedProps[strtoupper($compinfo2['type'])])) {
                             // check if component allows property
                             if ($this->log) {
                                 $this->log->log("ERROR 9, INPUT FILE:'{$inputdirFile}' iCalcreator: unvalid property for component '" . $compinfo2['type'] . "': '{$propName}'", PEAR_LOG_INFO);
                             }
                             continue;
                         }
                         if (isset($compinfo2['props'][$propName])) {
                             $fcn = 'create' . strtoupper(substr($propName, 0, 1)) . strtolower(substr($propName, 1));
                             if (!method_exists($scomp, $fcn)) {
                                 if ($this->log) {
                                     $this->log->log('ERROR 10 INPUT FILE:"' . $filename . '" iCalcreator: unknown property: "' . $propName . '" (' . $fcn . ')', PEAR_LOG_INFO);
                                 }
                                 continue;
                             }
                             $output = str_replace("{$calnl} ", '', rtrim($scomp->{$fcn}()));
                             $output = str_replace($propName . ';', '', $output);
                             $output = str_replace($propName . ':', '', $output);
                             $worksheet->writeString($row, $proporder[$propName], fixiCalString($output));
                         }
                     }
                     // end foreach( $proporder
                     if (isset($compinfo2['props']['X-PROP'])) {
                         while ($xprop = $scomp->getProperty()) {
                             $output = str_replace("{$calnl} ", '', rtrim($xprop[1]));
                             $worksheet->writeString($row, $proporder[$xprop[0]], fixiCalString($output));
                         }
                     }
                 }
                 // end foreach( $compinfo['sub']
             }
             // end if( isset( $compinfo['sub']['props'] ))
         }
         // end foreach
     }
     // end vtimezone
     $timeexec['zoneOk'] = microtime(TRUE);
     $maxColCount = count($proporder);
     /** fix property order list */
     $proporder = $proporderOrg;
     $proporder['TYPE'] = 0;
     $proporder['ORDER'] = 1;
     $props = array('UID', 'DTSTAMP', 'SUMMARY', 'DTSTART', 'DURATION', 'DTEND', 'DUE', 'RRULE', 'RDATE', 'EXRULE', 'EXDATE', 'DESCRIPTION', 'CATEGORIES', 'ORGANIZER', 'LOCATION', 'RESOURCES', 'CONTACT', 'URL', 'COMMENT', 'PRIORITY', 'ATTENDEE', 'CLASS', 'TRANSP', 'SEQUENCE', 'STATUS', 'COMPLETED', 'CREATED', 'LAST-MODIFIED', 'ACTION', 'TRIGGER', 'REPEAT', 'ATTACH', 'FREEBUSY', 'RELATED-TO', 'REQUEST-STATUS', 'GEO', 'PERCENT-COMPLETE', 'RECURRENCE-ID');
     $pix = 2;
     foreach ($props as $prop) {
         if (isset($proporder[$prop])) {
             continue;
         }
         if (in_array($prop, $propsToSkip)) {
             if ($this->log) {
                 $this->log->log("'{$prop}' removed from output", 7);
             }
             continue;
         }
         while (in_array($pix, $proporder)) {
             $pix++;
         }
         $proporder[$prop] = $pix++;
     }
     /** remove unused properties from and add x-props to property order list */
     if ($maxpropix < count($proporder) - 1) {
         $maxpropix = count($proporder) - 1;
     }
     $potmp = array();
     $potmp[0] = 'TYPE';
     $potmp[1] = 'ORDER';
     //  $potmp[2]                   =  'UID';
     foreach ($compsinfo as $cix => $compinfo) {
         if ('vtimezone' == $compinfo['type']) {
             continue;
         }
         foreach ($compinfo['props'] as $propName => $propcnt) {
             if (!in_array($propName, $potmp) && isset($proporder[$propName])) {
                 $potmp[$proporder[$propName]] = $propName;
             } elseif ('X-PROP' == $propName) {
                 $comp = $calendar->getComponent($compinfo['ordno']);
                 while ($xprop = $comp->getProperty()) {
                     if (!in_array($xprop[0], $potmp)) {
                         $maxpropix += 1;
                         $potmp[$maxpropix] = $xprop[0];
                     }
                     // end if
                 }
                 // while( $xprop
             }
             // end elseif( 'X-PROP'
         }
         // end foreach( $compinfo['props']
         if (isset($compinfo['sub'])) {
             foreach ($compinfo['sub'] as $compinfo2) {
                 foreach ($compinfo2['props'] as $propName => $propcnt) {
                     if (!in_array($propName, $potmp) && isset($proporder[$propName])) {
                         $potmp[$proporder[$propName]] = $propName;
                     } elseif ('X-PROP' == $propName) {
                         $scomp = $comp->getComponent($compinfo2['ordno']);
                         while ($xprop = $scomp->getProperty()) {
                             if (!in_array($xprop[0], $potmp)) {
                                 $maxpropix += 1;
                                 $potmp[$maxpropix] = $xprop[0];
                             }
                             // end if
                         }
                         // end while xprop
                     }
                     // end X-PROP
                 }
                 // end $compinfo['sub']['props']
             }
             // end foreach( $compinfo['sub']
         }
         // end if( isset( $compinfo['sub']
     }
     ksort($potmp, SORT_NUMERIC);
     $proporder = array_flip(array_values($potmp));
     if ($this->log) {
         $this->log->log("comp proporder=" . implode(',', array_flip($proporder)), 7);
     }
     if ($maxColCount < count($proporder)) {
         $maxColCount = count($proporder);
     }
     /** create header row */
     $row += 1;
     foreach ($proporder as $propName => $col) {
         if (isset($this->config[$propName])) {
             $worksheet->writeString($row, $col, $this->config[$propName], $format_bold);
             // check map of userfriendly name to iCal property name
             if ($this->log) {
                 $this->log->log("header row, col={$col}: {$propName}, replaced by " . $this->config[$propName], 7);
             }
         } else {
             $worksheet->writeString($row, $col, $propName, $format_bold);
         }
     }
     $allowedProps = array('VEVENT' => array('ATTACH', 'ATTENDEE', 'CATEGORIES', 'CLASS', 'COMMENT', 'CONTACT', 'CREATED', 'DESCRIPTION', 'DTEND', 'DTSTAMP', 'DTSTART', 'DURATION', 'EXDATE', 'RXRULE', 'GEO', 'LAST-MODIFIED', 'LOCATION', 'ORGANIZER', 'PRIORITY', 'RDATE', 'RECURRENCE-ID', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'SEQUENCE', 'STATUS', 'SUMMARY', 'TRANSP', 'UID', 'URL'), 'VTODO' => array('ATTACH', 'ATTENDEE', 'CATEGORIES', 'CLASS', 'COMMENT', 'COMPLETED', 'CONTACT', 'CREATED', 'DESCRIPTION', 'DTSTAMP', 'DTSTART', 'DUE', 'DURATION', 'EXDATE', 'EXRULE', 'GEO', 'LAST-MODIFIED', 'LOCATION', 'ORGANIZER', 'PERCENT', 'PRIORITY', 'RDATE', 'RECURRENCE-ID', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'SEQUENCE', 'STATUS', 'SUMMARY', 'UID', 'URL'), 'VJOURNAL' => array('ATTACH', 'ATTENDEE', 'CATEGORIES', 'CLASS', 'COMMENT', 'CONTACT', 'CREATED', 'DESCRIPTION', 'DTSTAMP', 'DTSTART', 'EXDATE', 'EXRULE', 'LAST-MODIFIED', 'ORGANIZER', 'RDATE', 'RECURRENCE-ID', 'RELATED-TO', 'RRULE', 'REQUEST-STATUS', 'SEQUENCE', 'STATUS', 'SUMMARY', 'UID', 'URL'), 'VFREEBUSY' => array('ATTENDEE', 'COMMENT', 'CONTACT', 'DTEND', 'DTSTAMP', 'DTSTART', 'DURATION', 'FREEBUSY', 'ORGANIZER', 'UID', 'URL'), 'VALARM' => array('ACTION', 'ATTACH', 'ATTENDEE', 'DESCRIPTION', 'DURATION', 'REPEAT', 'SUMMARY', 'TRIGGER'));
     /** create data rows */
     foreach ($compsinfo as $cix => $compinfo) {
         if ('vtimezone' == $compinfo['type']) {
             continue;
         }
         $row += 1;
         $worksheet->writeString($row, $proporder['TYPE'], $compinfo['type']);
         $worksheet->writeString($row, $proporder['ORDER'], $compinfo['ordno']);
         //    $worksheet->write(         $row, $proporder['UID'],   $compinfo['uid'] );
         $comp = $calendar->getComponent($compinfo['ordno']);
         foreach ($proporder as $propName => $col) {
             if ('TYPE' == $propName || 'ORDER' == $propName) {
                 continue;
             }
             if ('X-' == substr($propName, 0, 2)) {
                 continue;
             }
             if (!in_array($propName, $allowedProps[strtoupper($compinfo['type'])])) {
                 // check if component allows property
                 if ($this->log) {
                     $this->log->log("ERROR 11, INPUT FILE:'{$inputdirFile}' iCalcreator: unvalid property for component '" . $compinfo['type'] . "': '{$propName}'", PEAR_LOG_INFO);
                 }
                 continue;
             }
             if (isset($compinfo['props'][$propName])) {
                 switch ($propName) {
                     case 'LAST-MODIFIED':
                         $fcn = 'createLastModified';
                         break;
                     case 'RECURRENCE-ID':
                         $fcn = 'createRecurrenceid';
                         break;
                     case 'RELATED-TO':
                         $fcn = 'createRelatedTo';
                         break;
                     case 'REQUEST-STATUS':
                         $fcn = 'createRequestStatus';
                         break;
                     case 'PERCENT-COMPLETE':
                         $fcn = 'createPercentComplete';
                         break;
                     default:
                         $fcn = 'create' . strtoupper(substr($propName, 0, 1)) . strtolower(substr($propName, 1));
                 }
                 if (!method_exists($comp, $fcn)) {
                     if ($this->log) {
                         $this->log->log("ERROR 12 INPUT FILE:'{$filename}' iCalcreator: unknown property: '{$propName}' ({$fcn})", PEAR_LOG_INFO);
                     }
                     continue;
                 }
                 $output = str_replace("{$calnl} ", '', rtrim($comp->{$fcn}()));
                 $output = str_replace($propName . ';', '', $output);
                 $output = str_replace($propName . ':', '', $output);
                 $worksheet->writeString($row, $proporder[$propName], fixiCalString($output));
             }
         }
         // end foreach( $proporder
         if (isset($compinfo['props']['X-PROP'])) {
             while ($xprop = $comp->getProperty()) {
                 $output = str_replace("{$calnl} ", '', rtrim($xprop[1]));
                 $worksheet->writeString($row, $proporder[$xprop[0]], fixiCalString($output));
             }
         }
         if (isset($compinfo['sub'])) {
             foreach ($compinfo['sub'] as $compinfo2) {
                 $row += 1;
                 $worksheet->writeString($row, $proporder['TYPE'], $compinfo2['type']);
                 $worksheet->writeString($row, $proporder['ORDER'], $compinfo['ordno'] . ':' . $compinfo2['ordno']);
                 $scomp = $comp->getComponent($compinfo2['ordno']);
                 foreach ($proporder as $propName => $col) {
                     if ('TYPE' == $propName || 'ORDER' == $propName) {
                         continue;
                     }
                     if ('X-' == substr($propName, 0, 2)) {
                         continue;
                     }
                     if (!in_array($propName, $allowedProps[strtoupper($compinfo2['type'])])) {
                         // check if component allows property
                         if ($this->log) {
                             $this->log->log("ERROR 13, INPUT FILE:'{$inputdirFile}' iCalcreator: unvalid property for component '" . $compinfo2['type'] . "': '{$propName}'", PEAR_LOG_INFO);
                         }
                         continue;
                     }
                     if (isset($compinfo2['props'][$propName])) {
                         $fcn = 'create' . strtoupper(substr($propName, 0, 1)) . strtolower(substr($propName, 1));
                         if (!method_exists($scomp, $fcn)) {
                             if ($this->log) {
                                 $this->log->log("ERROR 14 INPUT FILE:'{$filename}' iCalcreator: unknown property: '{$propName}' ({$fcn})", PEAR_LOG_INFO);
                             }
                             continue;
                         }
                         $output = str_replace("{$calnl} ", '', rtrim($scomp->{$fcn}()));
                         $output = str_replace($propName . ';', '', $output);
                         $output = str_replace($propName . ':', '', $output);
                         $worksheet->writeString($row, $proporder[$propName], fixiCalString($output));
                     }
                     // end if( isset( $compinfo2['props'][$propName]
                 }
                 // end foreach( $proporder
                 if (isset($compinfo2['props']['X-PROP'])) {
                     while ($xprop = $scomp->getProperty()) {
                         $output = str_replace("{$calnl} ", '', rtrim($xprop[1]));
                         $output = str_replace('\\n ', chr(10), $output);
                         $worksheet->writeString($row, $proporder[$xprop[0]], fixiCalString($output));
                     }
                 }
                 // end if( isset( $compinfo2['props']['X-PROP']
             }
             // end foreach( $compinfo['sub']
         }
         // end if( isset( $compinfo['sub']
     }
     // foreach( $compsinfo as
     if ($this->log) {
         $timeexec['exit'] = microtime(TRUE);
         $msg = "'{$filename}'";
         $msg .= ' fileOk:' . number_format($timeexec['fileOk'] - $timeexec['start'], 5);
         $msg .= ' wrkbkOk:' . number_format($timeexec['wrkbkOk'] - $timeexec['fileOk'], 5);
         $msg .= ' infoOk:' . number_format($timeexec['infoOk'] - $timeexec['wrkbkOk'], 5);
         $msg .= ' zoneOk:' . number_format($timeexec['zoneOk'] - $timeexec['infoOk'], 5);
         $msg .= ' compOk:' . number_format($timeexec['exit'] - $timeexec['zoneOk'], 5);
         $msg .= ' total:' . number_format($timeexec['exit'] - $timeexec['start'], 5) . 'sec';
         $msg .= ', ' . ($row + 1) . " rows, {$maxColCount} cols";
         $this->log->log($msg, PEAR_LOG_DEBUG);
         $msg = "'{$filename}' (" . count($compsinfo) . ' components) start:' . date('H:i:s', $timeexec['start']);
         $msg .= ' total:' . number_format($timeexec['exit'] - $timeexec['start'], 5) . 'sec';
         if ($save) {
             $msg .= " saved as '{$outputdirFile}'";
         } else {
             $msg .= " redirected as '" . $outputFileParts['basename'] . "'";
         }
         $this->log->log($msg, PEAR_LOG_NOTICE);
     }
     /** Close and, opt., send the file */
     if ($this->log) {
         $this->log->flush();
     }
     $workbook->close();
     return TRUE;
 }
Esempio n. 2
0
 /**
  * Process vcalendar instance - add events to database.
  *
  * @param vcalendar $v    Calendar to retrieve data from.
  * @param array     $args Arbitrary arguments map.
  *
  * @throws Ai1ec_Parse_Exception
  *
  * @internal param stdClass $feed           Instance of feed (see Ai1ecIcs plugin).
  * @internal param string   $comment_status WP comment status: 'open' or 'closed'.
  * @internal param int      $do_show_map    Map display status (DB boolean: 0 or 1).
  *
  * @return int Count of events added to database.
  */
 public function add_vcalendar_events_to_db(vcalendar $v, array $args)
 {
     $feed = isset($args['feed']) ? $args['feed'] : null;
     $comment_status = isset($args['comment_status']) ? $args['comment_status'] : 'open';
     $do_show_map = isset($args['do_show_map']) ? $args['do_show_map'] : 0;
     $count = 0;
     $events_in_db = $args['events_in_db'];
     $v->sort();
     // Reverse the sort order, so that RECURRENCE-IDs are listed before the
     // defining recurrence events, and therefore take precedence during
     // caching.
     $v->components = array_reverse($v->components);
     // TODO: select only VEVENT components that occur after, say, 1 month ago.
     // Maybe use $v->selectComponents(), which takes into account recurrence
     // Fetch default timezone in case individual properties don't define it
     $timezone = $v->getProperty('X-WR-TIMEZONE');
     $timezone = (string) $timezone[1];
     // go over each event
     while ($e = $v->getComponent('vevent')) {
         // Event data array.
         $data = array();
         // =====================
         // = Start & end times =
         // =====================
         $start = $e->getProperty('dtstart', 1, true);
         $end = $e->getProperty('dtend', 1, true);
         // For cases where a "VEVENT" calendar component
         // specifies a "DTSTART" property with a DATE value type but none
         // of "DTEND" nor "DURATION" property, the event duration is taken to
         // be one day.  For cases where a "VEVENT" calendar component
         // specifies a "DTSTART" property with a DATE-TIME value type but no
         // "DTEND" property, the event ends on the same calendar date and
         // time of day specified by the "DTSTART" property.
         if (empty($end)) {
             // #1 if duration is present, assign it to end time
             $end = $e->getProperty('duration', 1, true, true);
             if (empty($end)) {
                 // #2 if only DATE value is set for start, set duration to 1 day
                 if (!isset($start['value']['hour'])) {
                     $end = array('value' => array('year' => $start['value']['year'], 'month' => $start['value']['month'], 'day' => $start['value']['day'] + 1, 'hour' => 0, 'min' => 0, 'sec' => 0));
                     if (isset($start['value']['tz'])) {
                         $end['value']['tz'] = $start['value']['tz'];
                     }
                 } else {
                     // #3 set end date to start time
                     $end = $start;
                 }
             }
         }
         $categories = $e->getProperty("CATEGORIES", false, true);
         $imported_cat = array();
         // If the user chose to preserve taxonomies during import, add categories.
         if ($categories && $feed->keep_tags_categories) {
             $imported_cat = $this->_add_categories_and_tags($categories['value'], $imported_cat, false, true);
         }
         $feed_categories = $feed->feed_category;
         if (!empty($feed_categories)) {
             $imported_cat = $this->_add_categories_and_tags($feed_categories, $imported_cat, false, false);
         }
         $tags = $e->getProperty("X-TAGS", false, true);
         $imported_tags = array();
         // If the user chose to preserve taxonomies during import, add tags.
         if ($tags && $feed->keep_tags_categories) {
             $imported_tags = $this->_add_categories_and_tags($tags[1]['value'], $imported_tags, true, true);
         }
         $feed_tags = $feed->feed_tags;
         if (!empty($feed_tags)) {
             $imported_tags = $this->_add_categories_and_tags($feed_tags, $imported_tags, true, true);
         }
         // Event is all-day if no time components are defined
         $allday = $this->_is_timeless($start['value']) && $this->_is_timeless($end['value']);
         // Also check the proprietary MS all-day field.
         $ms_allday = $e->getProperty('X-MICROSOFT-CDO-ALLDAYEVENT');
         if (!empty($ms_allday) && $ms_allday[1] == 'TRUE') {
             $allday = true;
         }
         $start = $this->_time_array_to_datetime($start, $timezone);
         $end = $this->_time_array_to_datetime($end, $timezone);
         if (false === $start || false === $end) {
             throw new Ai1ec_Parse_Exception('Failed to parse one or more dates given timezone "' . var_export($timezone, true) . '"');
             continue;
         }
         // If all-day, and start and end times are equal, then this event has
         // invalid end time (happens sometimes with poorly implemented iCalendar
         // exports, such as in The Event Calendar), so set end time to 1 day
         // after start time.
         if ($allday && $start->format() === $end->format()) {
             $end->adjust_day(+1);
         }
         $data += compact('start', 'end', 'allday');
         // =======================================
         // = Recurrence rules & recurrence dates =
         // =======================================
         if ($rrule = $e->createRrule()) {
             $rrule = explode(':', $rrule);
             $rrule = trim(end($rrule));
         }
         if ($exrule = $e->createExrule()) {
             $exrule = explode(':', $exrule);
             $exrule = trim(end($exrule));
         }
         if ($rdate = $e->createRdate()) {
             $rdate = explode(':', $rdate);
             $rdate = trim(end($rdate));
         }
         // ===================
         // = Exception dates =
         // ===================
         $exdate_array = array();
         if ($exdates = $e->createExdate()) {
             // We may have two formats:
             // one exdate with many dates ot more EXDATE rules
             $exdates = explode("EXDATE", $exdates);
             foreach ($exdates as $exd) {
                 if (empty($exd)) {
                     continue;
                 }
                 $exploded = explode(':', $exd);
                 $exdate_array[] = trim(end($exploded));
             }
         }
         // This is the local string.
         $exdate_loc = implode(',', $exdate_array);
         $gmt_exdates = array();
         // Now we convert the string to gmt. I must do it here
         // because EXDATE:date1,date2,date3 must be parsed
         if (!empty($exdate_loc)) {
             foreach (explode(',', $exdate_loc) as $date) {
                 $gmt_exdates[] = substr((string) $date, 0, 8);
             }
         }
         $exdate = implode(',', $gmt_exdates);
         // ========================
         // = Latitude & longitude =
         // ========================
         $latitude = $longitude = NULL;
         $geo_tag = $e->getProperty('geo');
         if (is_array($geo_tag)) {
             if (isset($geo_tag['latitude']) && isset($geo_tag['longitude'])) {
                 $latitude = (double) $geo_tag['latitude'];
                 $longitude = (double) $geo_tag['longitude'];
             }
         } else {
             if (!empty($geo_tag) && false !== strpos($geo_tag, ';')) {
                 list($latitude, $longitude) = explode(';', $geo_tag, 2);
                 $latitude = (double) $latitude;
                 $longitude = (double) $longitude;
             }
         }
         unset($geo_tag);
         if (NULL !== $latitude) {
             $data += compact('latitude', 'longitude');
             // Check the input coordinates checkbox, otherwise lat/long data
             // is not present on the edit event page
             $data['show_coordinates'] = 1;
         }
         // ===================
         // = Venue & address =
         // ===================
         $address = $venue = '';
         $location = $e->getProperty('location');
         $matches = array();
         // This regexp matches a venue / address in the format
         // "venue @ address" or "venue - address".
         preg_match('/\\s*(.*\\S)\\s+[\\-@]\\s+(.*)\\s*/', $location, $matches);
         // if there is no match, it's not a combined venue + address
         if (empty($matches)) {
             // if there is a comma, probably it's an address
             if (false === strpos($location, ',')) {
                 $venue = $location;
             } else {
                 $address = $location;
             }
         } else {
             $venue = isset($matches[1]) ? $matches[1] : '';
             $address = isset($matches[2]) ? $matches[2] : '';
         }
         // =====================================================
         // = Set show map status based on presence of location =
         // =====================================================
         if (1 === $do_show_map && NULL === $latitude && empty($address)) {
             $do_show_map = 0;
         }
         // ==================
         // = Cost & tickets =
         // ==================
         $cost = $e->getProperty('X-COST');
         $cost = $cost ? $cost[1] : '';
         $ticket_url = $e->getProperty('X-TICKETS-URL');
         $ticket_url = $ticket_url ? $ticket_url[1] : '';
         // ===============================
         // = Contact name, phone, e-mail =
         // ===============================
         $organizer = $e->getProperty('organizer');
         if ('MAILTO:' === substr($organizer, 0, 7) && false === strpos($organizer, '@')) {
             $organizer = substr($organizer, 7);
         }
         $contact = $e->getProperty('contact');
         $elements = explode(';', $contact, 4);
         foreach ($elements as $el) {
             $el = trim($el);
             // Detect e-mail address.
             if (false !== strpos($el, '@')) {
                 $data['contact_email'] = $el;
             } elseif (false !== strpos($el, '://')) {
                 $data['contact_url'] = $this->_parse_legacy_loggable_url($el);
             } elseif (preg_match('/\\d/', $el)) {
                 $data['contact_phone'] = $el;
             } else {
                 $data['contact_name'] = $el;
             }
         }
         if (!isset($data['contact_name']) || !$data['contact_name']) {
             // If no contact name, default to organizer property.
             $data['contact_name'] = $organizer;
         }
         // Store yet-unsaved values to the $data array.
         $data += array('recurrence_rules' => $rrule, 'exception_rules' => $exrule, 'recurrence_dates' => $rdate, 'exception_dates' => $exdate, 'venue' => $venue, 'address' => $address, 'cost' => $cost, 'ticket_url' => $this->_parse_legacy_loggable_url($ticket_url), 'show_map' => $do_show_map, 'ical_feed_url' => $feed->feed_url, 'ical_source_url' => $e->getProperty('url'), 'ical_organizer' => $organizer, 'ical_contact' => $contact, 'ical_uid' => $e->getProperty('uid'), 'categories' => array_keys($imported_cat), 'tags' => array_keys($imported_tags), 'feed' => $feed, 'post' => array('post_status' => 'publish', 'comment_status' => $comment_status, 'post_type' => AI1EC_POST_TYPE, 'post_author' => 1, 'post_title' => $e->getProperty('summary'), 'post_content' => stripslashes(str_replace('\\n', "\n", $e->getProperty('description')))));
         // Create event object.
         $event = $this->_registry->get('model.event', $data);
         $recurrence = $event->get('recurrence_rules');
         $search = $this->_registry->get('model.search');
         // first let's check by UID
         $matching_event_id = $search->get_matching_event_by_uid_and_url($event->get('ical_uid'), $event->get('ical_feed_url'));
         // if no result, perform the legacy check.
         if (null === $matching_event_id) {
             $matching_event_id = $search->get_matching_event_id($event->get('ical_uid'), $event->get('ical_feed_url'), $event->get('start'), !empty($recurrence));
         }
         if (null === $matching_event_id) {
             // =================================================
             // = Event was not found, so store it and the post =
             // =================================================
             $event->save();
         } else {
             // ======================================================
             // = Event was found, let's store the new event details =
             // ======================================================
             // Update the post
             $post = get_post($matching_event_id);
             if (null !== $post) {
                 $post->post_title = $event->get('post')->post_title;
                 $post->post_content = $event->get('post')->post_content;
                 wp_update_post($post);
                 // Update the event
                 $event->set('post_id', $matching_event_id);
                 $event->set('post', $post);
                 $event->save(true);
             }
         }
         // if the event was already present , unset it from the array so it's not deleted
         unset($events_in_db[$event->get('post_id')]);
         $count++;
     }
     return array('count' => $count, 'events_to_delete' => $events_in_db);
 }
Esempio n. 3
0
 /**
  * Returns modified exclusions structure for given event.
  *
  * @param vcalendar       $e          Vcalendar event object.
  * @param array           $exclusions Exclusions.
  * @param Ai1ec_Date_Time $start Date time object.
  *
  * @return array Modified exclusions structure.
  */
 protected function _add_recurring_events_exclusions($e, $exclusions, $start)
 {
     $recurrence_id = $e->getProperty('recurrence-id');
     if (false === $recurrence_id || !isset($recurrence_id['year']) || !isset($recurrence_id['month']) || !isset($recurrence_id['day'])) {
         return $exclusions;
     }
     $year = $month = $day = $hour = $min = $sec = null;
     extract($recurrence_id, EXTR_IF_EXISTS);
     $timezone = '';
     $exdate = sprintf('%04d%02d%02d', $year, $month, $day);
     if (null === $hour || null === $min || null === $sec) {
         $hour = $min = $sec = '00';
         $timezone = 'Z';
     }
     $exdate .= sprintf('T%02d%02d%02d%s', $hour, $min, $sec, $timezone);
     $exclusions[$e->getProperty('uid')][] = $exdate;
     return $exclusions;
 }
 /**
  * add_vcalendar_events_to_db method
  *
  * Process vcalendar instance - add events to database
  *
  * @param vcalendar $v              Calendar to retrieve data from
  * @param stdClass  $feed           Instance of feed (see Ai1ecIcs plugin)
  * @param string    $comment_status WP comment status: 'open' or 'closed'
  * @param int       $do_show_map    Map display status (DB boolean: 0 or 1)
  *
  * @return int Count of events added to database
  */
 public function add_vcalendar_events_to_db(vcalendar $v, $feed, $comment_status, $do_show_map = 0)
 {
     global $ai1ec_events_helper;
     $count = 0;
     $do_show_map = Ai1ec_Number_Utility::db_bool($do_show_map);
     $v->sort();
     // Reverse the sort order, so that RECURRENCE-IDs are listed before the
     // defining recurrence events, and therefore take precedence during
     // caching.
     $v->components = array_reverse($v->components);
     // TODO: select only VEVENT components that occur after, say, 1 month ago.
     // Maybe use $v->selectComponents(), which takes into account recurrence
     // Fetch default timezone in case individual properties don't define it
     $timezone = $v->getProperty('X-WR-TIMEZONE');
     $timezone = $timezone[1];
     // go over each event
     while ($e = $v->getComponent('vevent')) {
         // Event data array.
         $data = array();
         // =====================
         // = Start & end times =
         // =====================
         $start = $e->getProperty('dtstart', 1, true);
         $end = $e->getProperty('dtend', 1, true);
         // For cases where a "VEVENT" calendar component
         // specifies a "DTSTART" property with a DATE value type but no
         // "DTEND" nor "DURATION" property, the event's duration is taken to
         // be one day.  For cases where a "VEVENT" calendar component
         // specifies a "DTSTART" property with a DATE-TIME value type but no
         // "DTEND" property, the event ends on the same calendar date and
         // time of day specified by the "DTSTART" property.
         if (empty($end)) {
             // #1 if duration is present, assign it to end time
             $end = $e->getProperty('duration', 1, true, true);
             if (empty($end)) {
                 // #2 if only DATE value is set for start, set duration to 1 day
                 if (!isset($start['value']['hour'])) {
                     $end = array('year' => $start['value']['year'], 'month' => $start['value']['month'], 'day' => $start['value']['day'] + 1, 'hour' => 0, 'min' => 0, 'sec' => 0, 'tz' => $start['value']['tz']);
                 } else {
                     // #3 set end date to start time
                     $end = $start;
                 }
             }
         }
         // Event is all-day if no time components are defined
         $allday = !isset($start['value']['hour']);
         // Also check the proprietary MS all-day field.
         $ms_allday = $e->getProperty('X-MICROSOFT-CDO-ALLDAYEVENT');
         if (!empty($ms_allday) && $ms_allday[1] == 'TRUE') {
             $allday = true;
         }
         // convert times to GMT UNIX timestamps
         $start = $this->time_array_to_timestamp($start, $timezone);
         $end = $this->time_array_to_timestamp($end, $timezone);
         if (false === $start || false === $end) {
             trigger_error('Failed to parse one or more dates given timezone "' . var_export($timezone, true) . '".', E_USER_WARNING);
             continue;
         }
         // If all-day, and start and end times are equal, then this event has
         // invalid end time (happens sometimes with poorly implemented iCalendar
         // exports, such as in The Event Calendar), so set end time to 1 day
         // after start time.
         if ($allday && $start === $end) {
             $end += 24 * 60 * 60;
         }
         // Due to potential time zone differences (WP time zone vs. feed time
         // zone), must set all-day event start/end dates to midnight of the
         // respective days, in the *local* time zone.
         if ($allday) {
             $start = $ai1ec_events_helper->gmgetdate($start);
             $start = gmmktime(0, 0, 0, $start['mon'], $start['mday'], $start['year']);
             $start = $ai1ec_events_helper->local_to_gmt($start);
             $end = $ai1ec_events_helper->gmgetdate($end);
             $end = gmmktime(0, 0, 0, $end['mon'], $end['mday'], $end['year']);
             $end = $ai1ec_events_helper->local_to_gmt($end);
         }
         $data += compact('start', 'end', 'allday');
         // =======================================
         // = Recurrence rules & recurrence dates =
         // =======================================
         if ($rrule = $e->createRrule()) {
             $rrule = trim(end(explode(':', $rrule)));
         }
         if ($exrule = $e->createExrule()) {
             $exrule = trim(end(explode(':', $exrule)));
         }
         if ($rdate = $e->createRdate()) {
             $rdate = trim(end(explode(':', $rdate)));
         }
         // ===================
         // = Exception dates =
         // ===================
         $exdate_array = array();
         if ($exdates = $e->createExdate()) {
             // We may have two formats:
             // one exdate with many dates ot more EXDATE rules
             $exdates = explode("EXDATE", $exdates);
             foreach ($exdates as $exd) {
                 if (empty($exd)) {
                     continue;
                 }
                 $exdate_array[] = trim(end(explode(':', $exd)));
             }
         }
         // This is the local string.
         $exdate_loc = implode(',', $exdate_array);
         $gmt_exdates = array();
         // Now we convert the string to gmt. I must do it here
         // because EXDATE:date1,date2,date3 must be parsed
         if (!empty($exdate_loc)) {
             foreach (explode(',', $exdate_loc) as $date) {
                 // If the date is > 8 char that's a datetime, we just want the
                 // date part for the exclusion rules
                 if (strlen($date) > 8) {
                     $date = substr($date, 0, 8);
                 }
                 $gmt_exdates[] = $ai1ec_events_helper->exception_dates_to_gmt($date);
             }
         }
         $exdate = implode(',', $gmt_exdates);
         // ========================
         // = Latitude & longitude =
         // ========================
         $latitude = $longitude = NULL;
         $geo_tag = $e->getProperty('geo');
         if (!empty($geo_tag) && false !== strpos(';', $geo_tag)) {
             list($latitude, $longitude) = explode(';', $geo_tag, 2);
             $latitude = (double) $latitude;
             $longitude = (double) $longitude;
         }
         unset($geo_tag);
         if (NULL !== $latitude) {
             $data += compact('latitude', 'longitude');
         }
         // ===================
         // = Venue & address =
         // ===================
         $address = $venue = '';
         $location = $e->getProperty('location');
         $matches = array();
         // This regexp matches a venue / address in the format
         // "venue @ address" or "venue - address".
         preg_match('/\\s*(.*\\S)\\s+[\\-@]\\s+(.*)\\s*/', $location, $matches);
         // if there is no match, it's not a combined venue + address
         if (empty($matches)) {
             // if there is a comma, probably it's an address
             if (false === strpos($location, ',')) {
                 $venue = $location;
             } else {
                 $address = $location;
             }
         } else {
             $venue = isset($matches[1]) ? $matches[1] : '';
             $address = isset($matches[2]) ? $matches[2] : '';
         }
         // =====================================================
         // = Set show map status based on presence of location =
         // =====================================================
         if (1 === $do_show_map && NULL === $latitude && empty($address)) {
             $do_show_map = 0;
         }
         // ==================
         // = Cost & tickets =
         // ==================
         $cost = $e->getProperty('X-COST');
         $cost = $cost ? $cost[1] : '';
         $ticket_url = $e->getProperty('X-TICKETS-URL');
         $ticket_url = $ticket_url ? $ticket_url[1] : '';
         // ===============================
         // = Contact name, phone, e-mail =
         // ===============================
         $organizer = $e->getProperty('organizer');
         $contact = $e->getProperty('contact');
         $elements = explode(';', $contact, 4);
         foreach ($elements as $el) {
             $el = trim($el);
             // Detect e-mail address.
             if (false !== strpos($el, '@')) {
                 $data['contact_email'] = $el;
             } elseif (false !== strpos($el, '://')) {
                 $data['contact_url'] = $el;
             } elseif (preg_match('/\\d/', $el)) {
                 $data['contact_phone'] = $el;
             } else {
                 $data['contact_name'] = $el;
             }
         }
         if (!$data['contact_name']) {
             // If no contact name, default to organizer property.
             $data['contact_name'] = $organizer;
         }
         // Store yet-unsaved values to the $data array.
         $data += array('recurrence_rules' => $rrule, 'exception_rules' => $exrule, 'recurrence_dates' => $rdate, 'exception_dates' => $exdate, 'venue' => $venue, 'address' => $address, 'cost' => $cost, 'ticket_url' => $ticket_url, 'show_map' => $do_show_map, 'ical_feed_url' => $feed->feed_url, 'ical_source_url' => $e->getProperty('url'), 'ical_organizer' => $organizer, 'ical_contact' => $contact, 'ical_uid' => $e->getProperty('uid'), 'categories' => $feed->feed_category, 'tags' => $feed->feed_tags, 'feed' => $feed, 'post' => array('post_status' => 'publish', 'comment_status' => $comment_status, 'post_type' => AI1EC_POST_TYPE, 'post_author' => 1, 'post_title' => $e->getProperty('summary'), 'post_content' => stripslashes(str_replace('\\n', "\n", $e->getProperty('description')))));
         // Create event object.
         $event = new Ai1ec_Event($data);
         // TODO: when singular events change their times in an ICS feed from one
         // import to another, the matching_event_id is null, which is wrong. We
         // want to match that event that previously had a different time.
         // However, we also want the function to NOT return a matching event in
         // the case of recurring events, and different events with different
         // RECURRENCE-IDs... ponder how to solve this.. may require saving the
         // RECURRENCE-ID as another field in the database.
         $matching_event_id = $ai1ec_events_helper->get_matching_event_id($event->ical_uid, $event->ical_feed_url, $event->start, !empty($event->recurrence_rules));
         if (is_null($matching_event_id)) {
             // =================================================
             // = Event was not found, so store it and the post =
             // =================================================
             $event->save();
         } else {
             // ======================================================
             // = Event was found, let's store the new event details =
             // ======================================================
             // Update the post
             $post = get_post($matching_event_id);
             $post->post_title = $event->post->post_title;
             $post->post_content = $event->post->post_content;
             wp_update_post($post);
             // Update the event
             $event->post_id = $matching_event_id;
             $event->post = $post;
             $event->save(true);
             // Delete event's cache
             $ai1ec_events_helper->delete_event_cache($matching_event_id);
         }
         // Regenerate event's cache
         $ai1ec_events_helper->cache_event($event);
         $count++;
     }
     return $count;
 }
/**
 * function iCal2csv
 *
 * Convert iCal file to csv format and send file to browser (default) or save csv file to disk
 * Definition iCal  : rcf2445, http://localhost/work/kigkonsult.se/downloads/index.php#rfc2445
 * Definition csv   : http://en.wikipedia.org/wiki/Comma-separated_values
 * Using iCalcreator: http://localhost/work/kigkonsult.se/downloads/index.php#iCalcreator
 * ical directory/file read/write error OR iCalcreator parse error will be directed to error_log/log
 *
 * @author Kjell-Inge Gustafsson <*****@*****.**>
 * @since 2.0 - 2009-03-27
 * @param string $filename      file to convert (incl. opt. directory)
 * @param array  $conf          opt, default FALSE(=array('del'=>'"','sep'=>',', 'nl'=>'\n'), delimiter, separator and newline characters
 *                              escape sequences will be expanded, '\n' will be used as "\n" etc.
 *                              also map iCal property names to user friendly names, ex. 'DTSTART' => 'startdate'
 *                              also order output columns, ex. 2 => 'DTSTART' (2=first order column, 3 next etc)
 *                              also properties to skip, ex. 'skip' => array( 'CREATED', 'PRIORITY' );
 * @param bool   $save          opt, default FALSE, TRUE=save to disk
 * @param string $diskfilename  opt, filename for file to save or else taken from $filename + 'csv' extension
 * @param object $log           opt, default FALSE (error_log), writes log to file using PEAR LOG or eClog class
 * @return bool                 returns FALSE when error
 */
function iCal2csv($filename, $conf = FALSE, $save = FALSE, $diskfilename = FALSE, $log = FALSE)
{
    if ($log) {
        $timeexec = array('start' => microtime(TRUE));
    }
    $iCal2csv_VERSION = 'iCal2csv 2.0';
    if (!function_exists('fileCheckRead')) {
        require_once 'fileCheck.php';
    }
    if (!class_exists('vcalendar', FALSE)) {
        require_once 'iCalcreator.class.php';
    }
    if ($log) {
        $log->log("{$iCal2csv_VERSION} input={$filename}, conf=" . var_export($conf, TRUE) . ", save={$save}, diskfilename={$diskfilename}", 7);
    }
    $remoteInput = 'http://' == strtolower(substr($filename, 0, 7)) || 'webcal://' == strtolower(substr($filename, 0, 9)) ? TRUE : FALSE;
    // field DELimiter && field SEParator && NewLine character(-s) etc.
    if (!$conf) {
        $conf = array();
    }
    if (!isset($conf['del'])) {
        $conf['del'] = '"';
    }
    if (!isset($conf['sep'])) {
        $conf['sep'] = ',';
    }
    if (!isset($conf['nl'])) {
        $conf['nl'] = "\n";
    }
    foreach ($conf as $key => $value) {
        if ('skip' == $key) {
            foreach ($value as $six => $skipp) {
                $conf['skip'][$six] = strtoupper($skipp);
            }
        } elseif ('2' <= $key && '99' > $key) {
            $conf[$key] = strtoupper($value);
            if ($log) {
                $log->log("{$iCal2csv_VERSION} column {$key} contains " . strtoupper($value), 7);
            }
        } elseif (in_array($key, array('del', 'sep', 'nl'))) {
            $conf[$key] = "{$value}";
        } else {
            $conf[strtoupper($key)] = $value;
            if ($log) {
                $log->log("{$iCal2csv_VERSION} " . strtoupper($key) . " mapped to {$value}", 7);
            }
        }
    }
    /* create path and filename */
    if ($remoteInput) {
        $inputFileParts = parse_url($filename);
        $inputFileParts = array_merge($inputFileParts, pathinfo($inputFileParts['path']));
        if (!$diskfilename) {
            $diskfilename = $inputFileParts['filename'] . '.csv';
        }
    } else {
        if (FALSE === ($filename = fileCheckRead($filename, $log))) {
            if ($log) {
                $log->log("{$iCal2csv_VERSION} (" . number_format(microtime(TRUE) - $timeexec['start'], 5) . ')');
                $log->flush();
            }
            return FALSE;
        }
        $inputFileParts = pathinfo($filename);
        if (!$diskfilename) {
            $diskfilename = $inputFileParts['dirname'] . DIRECTORY_SEPARATOR . $inputFileParts['filename'] . '.csv';
        }
    }
    $outputFileParts = pathinfo($diskfilename);
    if ($save) {
        if (FALSE === ($diskfilename = fileCheckWrite($outputFileParts['dirname'] . DIRECTORY_SEPARATOR . $outputFileParts['basename'], $log))) {
            if ($log) {
                $log->log("{$iCal2csv_VERSION} (" . number_format(microtime(TRUE) - $timeexec['start'], 5) . ')');
                $log->flush();
            }
            return FALSE;
        }
    }
    if ($log) {
        $msg = $iCal2csv_VERSION . ' INPUT FILE:"' . $inputFileParts['dirname'] . DIRECTORY_SEPARATOR . $inputFileParts['basename'] . '"';
        if ($save) {
            $msg .= ' OUTPUT FILE: "' . $outputFileParts['dirname'] . DIRECTORY_SEPARATOR . $outputFileParts['basename'] . '"';
        }
        $log->log($msg, 7);
    }
    /* iCalcreator check, read and parse input iCal file */
    $calendar = new vcalendar();
    $calnl = $calendar->getConfig('nl');
    if ($remoteInput) {
        if (FALSE === $calendar->setConfig('url', $filename)) {
            $msg = $iCal2csv_VERSION . ' ERROR 3 INPUT FILE:"' . $filename . '" iCalcreator: invalid url';
            if ($log) {
                $log->log($msg, 3);
                $log->flush();
            } else {
                error_log($msg);
            }
            return FALSE;
        }
    } else {
        if (FALSE === $calendar->setConfig('directory', $inputFileParts['dirname'])) {
            $msg = $iCal2csv_VERSION . ' ERROR 4 INPUT FILE:"' . $filename . '" iCalcreator: invalid directory: "' . $inputFileParts['dirname'] . '"';
            if ($log) {
                $log->log($msg, 3);
                $log->flush();
            } else {
                error_log($msg);
            }
            return FALSE;
        }
        if (FALSE === $calendar->setConfig('filename', $inputFileParts['basename'])) {
            $msg = $iCal2csv_VERSION . ' ERROR 5 INPUT FILE:"' . $filename . '" iCalcreator: invalid filename: "' . $inputFileParts['basename'] . '"';
            if ($log) {
                $log->log($msg, 3);
                $log->flush();
            } else {
                error_log($msg);
            }
            return FALSE;
        }
    }
    if (FALSE === $calendar->parse()) {
        $msg = $iCal2csv_VERSION . ' ERROR 6 INPUT FILE:"' . $filename . '" iCalcreator parse error';
        if ($log) {
            $log->log($msg, 3);
            $log->flush();
        } else {
            error_log($msg);
        }
        return FALSE;
    }
    if ($log) {
        $timeexec['fileOk'] = microtime(TRUE);
    }
    if (!function_exists('iCaldate2timestamp')) {
        function iCaldate2timestamp($d)
        {
            if (6 > count($d)) {
                return mktime(0, 0, 0, $d['month'], $d['day'], $d['year']);
            } else {
                return mktime($d['hour'], $d['min'], $d['sec'], $d['month'], $d['day'], $d['year']);
            }
        }
    }
    if (!function_exists('fixiCalString')) {
        function fixiCalString($s)
        {
            $s = str_replace('\\,', ',', $s);
            $s = str_replace('\\;', ';', $s);
            $s = str_replace('\\n ', chr(10), $s);
            $s = str_replace('\\\\', '\\', $s);
            return $s;
        }
    }
    /* create output array */
    $rows = array();
    /* info rows */
    $rows[] = array('kigkonsult.se', ICALCREATOR_VERSION, $iCal2csv_VERSION, date('Y-m-d H:i:s'));
    $filename = $remoteInput ? $filename : $inputFileParts['basename'];
    $rows[] = array('iCal input', $filename, 'csv output', $outputFileParts['basename']);
    if ($prop = $calendar->getProperty('CALSCALE')) {
        $rows[] = array('CALSCALE', $prop);
    }
    if ($prop = $calendar->getProperty('METHOD')) {
        $rows[] = array('METHOD', $prop);
    }
    while ($xprop = $calendar->getProperty()) {
        $rows[] = array($xprop[0], $xprop[1]);
    }
    if ($log) {
        $timeexec['infoOk'] = microtime(TRUE);
    }
    /* fix vtimezone property order list */
    $proporder = array();
    foreach ($conf as $key => $value) {
        if ('2' <= $key && '99' > $key) {
            $proporder[$value] = $key;
            if ($log) {
                $log->log("{$iCal2csv_VERSION} {$value} in column {$key}", 7);
            }
        }
    }
    $proporder['TYPE'] = 0;
    $proporder['ORDER'] = 1;
    $props = array('TZID', 'LAST-MODIFIED', 'TZURL', 'DTSTART', 'TZOFFSETTO', 'TZOFFSETFROM', 'TZOFFSETTFROM', 'COMMENT', 'RRULE', 'RDATE', 'TZNAME');
    $pix = 2;
    foreach ($props as $prop) {
        if (isset($proporder[$prop])) {
            continue;
        }
        if (isset($conf['skip']) && in_array($prop, $conf['skip'])) {
            if ($log) {
                $log->log("{$iCal2csv_VERSION} {$prop} removed from output", 7);
            }
            continue;
        }
        while (in_array($pix, $proporder)) {
            $pix++;
        }
        $proporder[$prop] = $pix++;
    }
    /* remove unused properties from and add x-props to property order list */
    $maxpropix = 11;
    if ($maxpropix != count($proporder) - 1) {
        $maxpropix = count($proporder) - 1;
    }
    $compsinfo = $calendar->getConfig('compsinfo');
    $potmp = array();
    $potmp[0] = 'TYPE';
    $potmp[1] = 'ORDER';
    foreach ($compsinfo as $cix => $compinfo) {
        if ('vtimezone' != $compinfo['type']) {
            continue;
        }
        $comp = $calendar->getComponent($compinfo['ordno']);
        foreach ($compinfo['props'] as $propName => $propcnt) {
            if (!in_array($propName, $potmp) && isset($proporder[$propName])) {
                $potmp[$proporder[$propName]] = $propName;
            } elseif ('X-PROP' == $propName) {
                while ($xprop = $comp->getProperty()) {
                    if (!in_array($xprop[0], $potmp)) {
                        $maxpropix += 1;
                        $potmp[$maxpropix] = $xprop[0];
                    }
                    // end if
                }
                // end while xprop
            }
            // end X-PROP
        }
        // end $compinfo['props']
        if (isset($compinfo['sub'])) {
            foreach ($compinfo['sub'] as $compinfo2) {
                foreach ($compinfo2['props'] as $propName => $propcnt) {
                    if (!in_array($propName, $potmp) && isset($proporder[$propName])) {
                        $potmp[$proporder[$propName]] = $propName;
                    } elseif ('X-PROP' == $propName) {
                        $scomp = $comp->getComponent($compinfo2['ordno']);
                        while ($xprop = $scomp->getProperty()) {
                            if (!in_array($xprop[0], $potmp)) {
                                $maxpropix += 1;
                                $potmp[$maxpropix] = $xprop[0];
                            }
                            // end if
                        }
                        // end while xprop
                    }
                    // end X-PROP
                }
                // end $compinfo['sub']['props']
            }
            // end foreach( $compinfo['sub']
        }
        // end if( isset( $compinfo['sub']
    }
    // end foreach compinfo - vtimezone
    ksort($potmp, SORT_NUMERIC);
    if ('2.6' == substr(ICALCREATOR_VERSION, -3)) {
        foreach ($potmp as $k => $v) {
            // iCalcreator 2.6 bug fix
            if ('TZOFFSETTFROM' == $v) {
                $potmp[$k] = 'TZOFFSETFROM';
            }
        }
    }
    $proporder = array_flip(array_values($potmp));
    if ($log) {
        $log->log("{$iCal2csv_VERSION} zone proporder=" . implode(',', array_flip($proporder)), 7);
    }
    /* create vtimezone info */
    $row = count($rows) - 1;
    if (2 < count($proporder)) {
        $row += 1;
        /* create vtimezone header row */
        foreach ($proporder as $propName => $col) {
            if (isset($conf[$propName])) {
                $rows[$row][$col] = $conf[$propName];
                // check map of userfriendly name to iCal property name
                if ($log) {
                    $log->log("{$iCal2csv_VERSION} header row, col={$col}: {$propName}, replaced by " . $conf[$propName], 7);
                }
            } else {
                $rows[$row][$col] = $propName;
            }
        }
        $allowedProps = array('VTIMEZONE' => array('TZID', 'LAST-MODIFIED', 'TZURL'), 'STANDARD' => array('DTSTART', 'TZOFFSETTO', 'TZOFFSETFROM', 'COMMENT', 'RDATE', 'RRULE', 'TZNAME'), 'DAYLIGHT' => array('DTSTART', 'TZOFFSETTO', 'TZOFFSETFROM', 'COMMENT', 'RDATE', 'RRULE', 'TZNAME'));
        /* create vtimezone data rows */
        foreach ($compsinfo as $cix => $compinfo) {
            if ('vtimezone' != $compinfo['type']) {
                continue;
            }
            $row += 1;
            foreach ($proporder as $propName => $col) {
                $rows[$row][] = '';
            }
            // set all cells empty
            $rows[$row][$proporder['TYPE']] = $compinfo['type'];
            $rows[$row][$proporder['ORDER']] = $compinfo['ordno'];
            $comp = $calendar->getComponent($compinfo['ordno']);
            foreach ($proporder as $propName => $col) {
                if ('TYPE' == $propName || 'ORDER' == $propName) {
                    continue;
                }
                if ('X-' == substr($propName, 0, 2)) {
                    continue;
                }
                if (!in_array($propName, $allowedProps['VTIMEZONE'])) {
                    // check if component allows property
                    continue;
                }
                if (isset($compinfo['props'][$propName])) {
                    if ('LAST-MODIFIED' == $propName) {
                        $fcn = 'createLastModified';
                    } else {
                        $fcn = 'create' . strtoupper(substr($propName, 0, 1)) . strtolower(substr($propName, 1));
                    }
                    if (!method_exists($comp, $fcn)) {
                        $msg = $iCal2csv_VERSION . ' ERROR 7 INPUT FILE:"' . $filename . '" iCalcreator: unknown property: "' . $propName . '" (' . $fcn . ')';
                        if ($log) {
                            $log->log($msg, 3);
                        } else {
                            error_log($msg);
                        }
                        continue;
                    }
                    $output = str_replace("{$calnl} ", '', rtrim($comp->{$fcn}()));
                    $output = str_replace($propName . ';', '', $output);
                    $output = str_replace($propName . ':', '', $output);
                    $rows[$row][$proporder[$propName]] = fixiCalString($output);
                }
            }
            // end foreach( $proporder
            if (isset($compinfo['props']['X-PROP'])) {
                while ($xprop = $comp->getProperty()) {
                    $output = str_replace("{$calnl} ", '', rtrim($xprop[1]));
                    $rows[$row][$proporder[$xprop[0]]] = fixiCalString($output);
                }
            }
            if (isset($compinfo['sub'])) {
                foreach ($compinfo['sub'] as $compinfo2) {
                    $row += 1;
                    foreach ($proporder as $propName => $col) {
                        $rows[$row][] = '';
                    }
                    // set all cells empty
                    $rows[$row][$proporder['TYPE']] = $compinfo2['type'];
                    $rows[$row][$proporder['ORDER']] = $compinfo['ordno'] . ':' . $compinfo2['ordno'];
                    $scomp = $comp->getComponent($compinfo2['ordno']);
                    foreach ($proporder as $propName => $col) {
                        if ('TYPE' == $propName || 'ORDER' == $propName) {
                            continue;
                        }
                        if ('X-' == substr($propName, 0, 2)) {
                            continue;
                        }
                        if (!in_array($propName, $allowedProps[strtoupper($compinfo2['type'])])) {
                            // check if component allows property
                            continue;
                        }
                        if ('2.6' == substr(ICALCREATOR_VERSION, -3) && 'TZOFFSETFROM' == $propName) {
                            $propName = 'TZOFFSETTFROM';
                        }
                        // iCalcreator 2.6 bug fix
                        if (isset($compinfo2['props'][$propName])) {
                            if ('2.6' == substr(ICALCREATOR_VERSION, -3) && 'TZOFFSETTFROM' == $propName) {
                                $propName = 'TZOFFSETFROM';
                            }
                            // iCalcreator 2.6 bug fix
                            $fcn = 'create' . strtoupper(substr($propName, 0, 1)) . strtolower(substr($propName, 1));
                            if (!method_exists($scomp, $fcn)) {
                                $msg = $iCal2csv_VERSION . ' ERROR 8 INPUT FILE:"' . $filename . '" iCalcreator: unknown property: "' . $propName . '" (' . $fcn . ')';
                                if ($log) {
                                    $log->log($msg, 3);
                                } else {
                                    error_log($msg);
                                }
                                continue;
                            }
                            $output = str_replace("{$calnl} ", '', rtrim($scomp->{$fcn}()));
                            $output = str_replace($propName . ';', '', $output);
                            $output = str_replace($propName . ':', '', $output);
                            $rows[$row][$proporder[$propName]] = fixiCalString($output);
                        }
                    }
                    // end foreach( $proporder
                    if (isset($compinfo2['props']['X-PROP'])) {
                        while ($xprop = $scomp->getProperty()) {
                            $output = str_replace("{$calnl} ", '', rtrim($xprop[1]));
                            $rows[$row][$proporder[$xprop[0]]] = fixiCalString($output);
                        }
                    }
                }
                // end foreach( $compinfo['sub']
            }
            // end if( isset( $compinfo['sub']['props'] ))
        }
        // end foreach
    }
    // end vtimezone
    if ($log) {
        $timeexec['zoneOk'] = microtime(TRUE);
    }
    $maxColCount = count($proporder);
    /* fix property order list */
    $proporder = array();
    foreach ($conf as $key => $value) {
        if ('2' <= $key && '99' > $key) {
            $proporder[$value] = $key;
            if ($log) {
                $log->log("{$iCal2csv_VERSION} {$value} in column {$key}", 7);
            }
        }
    }
    $proporder['TYPE'] = 0;
    $proporder['ORDER'] = 1;
    $props = array('UID', 'DTSTAMP', 'SUMMARY', 'DTSTART', 'DURATION', 'DTEND', 'DUE', 'RRULE', 'RDATE', 'EXRULE', 'EXDATE', 'DESCRIPTION', 'CATEGORIES', 'ORGANIZER', 'LOCATION', 'RESOURCES', 'CONTACT', 'URL', 'COMMENT', 'PRIORITY', 'ATTENDEE', 'CLASS', 'TRANSP', 'SEQUENCE', 'STATUS', 'COMPLETED', 'CREATED', 'LAST-MODIFIED', 'ACTION', 'TRIGGER', 'REPEAT', 'ATTACH', 'FREEBUSY', 'RELATED-TO', 'REQUEST-STATUS', 'GEO', 'PERCENT-COMPLETE', 'RECURRENCE-ID');
    $pix = 2;
    foreach ($props as $prop) {
        if (isset($proporder[$prop])) {
            continue;
        }
        if (isset($conf['skip']) && in_array($prop, $conf['skip'])) {
            if ($log) {
                $log->log("{$iCal2csv_VERSION} {$prop} removed from output", 7);
            }
            continue;
        }
        while (in_array($pix, $proporder)) {
            $pix++;
        }
        $proporder[$prop] = $pix++;
    }
    /* remove unused properties from and add x-props to property order list */
    if ($maxpropix < count($proporder) - 1) {
        $maxpropix = count($proporder) - 1;
    }
    $potmp = array();
    $potmp[0] = 'TYPE';
    $potmp[1] = 'ORDER';
    //  $potmp[2]                   =  'UID';
    foreach ($compsinfo as $cix => $compinfo) {
        if ('vtimezone' == $compinfo['type']) {
            continue;
        }
        foreach ($compinfo['props'] as $propName => $propcnt) {
            if (!in_array($propName, $potmp) && isset($proporder[$propName])) {
                $potmp[$proporder[$propName]] = $propName;
            } elseif ('X-PROP' == $propName) {
                $comp = $calendar->getComponent($compinfo['ordno']);
                while ($xprop = $comp->getProperty()) {
                    if (!in_array($xprop[0], $potmp)) {
                        $maxpropix += 1;
                        $potmp[$maxpropix] = $xprop[0];
                    }
                    // end if
                }
                // while( $xprop
            }
            // end elseif( 'X-PROP'
        }
        // end foreach( $compinfo['props']
        if (isset($compinfo['sub'])) {
            foreach ($compinfo['sub'] as $compinfo2) {
                foreach ($compinfo2['props'] as $propName => $propcnt) {
                    if (!in_array($propName, $potmp) && isset($proporder[$propName])) {
                        $potmp[$proporder[$propName]] = $propName;
                    } elseif ('X-PROP' == $propName) {
                        $scomp = $comp->getComponent($compinfo2['ordno']);
                        while ($xprop = $scomp->getProperty()) {
                            if (!in_array($xprop[0], $potmp)) {
                                $maxpropix += 1;
                                $potmp[$maxpropix] = $xprop[0];
                            }
                            // end if
                        }
                        // end while xprop
                    }
                    // end X-PROP
                }
                // end $compinfo['sub']['props']
            }
            // end foreach( $compinfo['sub']
        }
        // end if( isset( $compinfo['sub']
    }
    ksort($potmp, SORT_NUMERIC);
    $proporder = array_flip(array_values($potmp));
    if ($log) {
        $log->log("{$iCal2csv_VERSION} comp proporder=" . implode(',', array_flip($proporder)), 7);
    }
    if ($maxColCount < count($proporder)) {
        $maxColCount = count($proporder);
    }
    /* create header row */
    $row += 1;
    foreach ($proporder as $propName => $col) {
        if (isset($conf[$propName])) {
            $rows[$row][$col] = $conf[$propName];
            // check map of userfriendly name to iCal property name
            if ($log) {
                $log->log("{$iCal2csv_VERSION} header row, col={$col}: {$propName}, replaced by " . $conf[$propName], 7);
            }
        } else {
            $rows[$row][$col] = $propName;
        }
    }
    $allowedProps = array('VEVENT' => array('ATTACH', 'ATTENDEE', 'CATEGORIES', 'CLASS', 'COMMENT', 'CONTACT', 'CREATED', 'DESCRIPTION', 'DTEND', 'DTSTAMP', 'DTSTART', 'DURATION', 'EXDATE', 'RXRULE', 'GEO', 'LAST-MODIFIED', 'LOCATION', 'ORGANIZER', 'PRIORITY', 'RDATE', 'RECURRENCE-ID', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'SEQUENCE', 'STATUS', 'SUMMARY', 'TRANSP', 'UID', 'URL'), 'VTODO' => array('ATTACH', 'ATTENDEE', 'CATEGORIES', 'CLASS', 'COMMENT', 'COMPLETED', 'CONTACT', 'CREATED', 'DESCRIPTION', 'DTSTAMP', 'DTSTART', 'DUE', 'DURATION', 'EXATE', 'EXRULE', 'GEO', 'LAST-MODIFIED', 'LOCATION', 'ORGANIZER', 'PERCENT', 'PRIORITY', 'RDATE', 'RECURRENCE-ID', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'SEQUENCE', 'STATUS', 'SUMMARY', 'UID', 'URL'), 'VJOURNAL' => array('ATTACH', 'ATTENDEE', 'CATEGORIES', 'CLASS', 'COMMENT', 'CONTACT', 'CREATED', 'DESCRIPTION', 'DTSTAMP', 'DTSTART', 'EXDATE', 'EXRULE', 'LAST-MODIFIED', 'ORGANIZER', 'RDATE', 'RECURRENCE-ID', 'RELATED-TO', 'RRULE', 'REQUEST-STATUS', 'SEQUENCE', 'STATUS', 'SUMMARY', 'UID', 'URL'), 'VFREEBUSY' => array('ATTENDEE', 'COMMENT', 'CONTACT', 'DTEND', 'DTSTAMP', 'DTSTART', 'DURATION', 'FREEBUSY', 'ORGANIZER', 'UID', 'URL'), 'VALARM' => array('ACTION', 'ATTACH', 'ATTENDEE', 'DESCRIPTION', 'DURATION', 'REPEAT', 'TRANSP', 'TRIGGER'));
    /* create data rows */
    foreach ($compsinfo as $cix => $compinfo) {
        if ('vtimezone' == $compinfo['type']) {
            continue;
        }
        $row += 1;
        foreach ($proporder as $propName => $col) {
            $rows[$row][] = '';
        }
        // set all cells empty
        $rows[$row][$proporder['TYPE']] = $compinfo['type'];
        $rows[$row][$proporder['ORDER']] = $compinfo['ordno'];
        //    $rows[$row][$proporder['UID']]   = $compinfo['uid'];
        $comp = $calendar->getComponent($compinfo['ordno']);
        foreach ($proporder as $propName => $col) {
            if ('TYPE' == $propName || 'ORDER' == $propName) {
                continue;
            }
            if ('X-' == substr($propName, 0, 2)) {
                continue;
            }
            if (!in_array($propName, $allowedProps[strtoupper($compinfo['type'])])) {
                // check if component allows property
                continue;
            }
            if (isset($compinfo['props'][$propName])) {
                switch ($propName) {
                    case 'LAST-MODIFIED':
                        $fcn = 'createLastModified';
                        break;
                    case 'RECURRENCE-ID':
                        $fcn = 'createRecurrenceid';
                        break;
                    case 'RELATED-TO':
                        $fcn = 'createRelatedTo';
                        break;
                    case 'REQUEST-STATUS':
                        $fcn = 'createRequestStatus';
                        break;
                    case 'PERCENT-COMPLETE':
                        $fcn = 'createPercentComplete';
                        break;
                    default:
                        $fcn = 'create' . strtoupper(substr($propName, 0, 1)) . strtolower(substr($propName, 1));
                }
                if (!method_exists($comp, $fcn)) {
                    $msg = $iCal2csv_VERSION . ' ERROR 9 INPUT FILE:"' . $filename . '" iCalcreator: unknown property: "' . $propName . '" (' . $fcn . ')';
                    if ($log) {
                        $log->log($msg, 3);
                    } else {
                        error_log($msg);
                    }
                    continue;
                }
                $output = str_replace("{$calnl} ", '', rtrim($comp->{$fcn}()));
                $output = str_replace($propName . ';', '', $output);
                $output = str_replace($propName . ':', '', $output);
                $rows[$row][$proporder[$propName]] = fixiCalString($output);
            }
        }
        // end foreach( $proporder
        if (isset($compinfo['props']['X-PROP'])) {
            while ($xprop = $comp->getProperty()) {
                $output = str_replace("{$calnl} ", '', rtrim($xprop[1]));
                $rows[$row][$proporder[$xprop[0]]] = fixiCalString($output);
            }
        }
        if (isset($compinfo['sub'])) {
            foreach ($compinfo['sub'] as $compinfo2) {
                $row += 1;
                foreach ($proporder as $propName => $col) {
                    $rows[$row][] = '';
                }
                // set all cells empty
                $rows[$row][$proporder['TYPE']] = $compinfo2['type'];
                $rows[$row][$proporder['ORDER']] = $compinfo['ordno'] . ':' . $compinfo2['ordno'];
                $scomp = $comp->getComponent($compinfo2['ordno']);
                foreach ($proporder as $propName => $col) {
                    if ('TYPE' == $propName || 'ORDER' == $propName) {
                        continue;
                    }
                    if ('X-' == substr($propName, 0, 2)) {
                        continue;
                    }
                    if (!in_array($propName, $allowedProps[strtoupper($compinfo2['type'])])) {
                        // check if component allows property
                        continue;
                    }
                    if (isset($compinfo2['props'][$propName])) {
                        $fcn = 'create' . strtoupper(substr($propName, 0, 1)) . strtolower(substr($propName, 1));
                        if (!method_exists($scomp, $fcn)) {
                            $msg = $iCal2csv_VERSION . ' ERROR 10 INPUT FILE:"' . $filename . '" iCalcreator: unknown property: "' . $propName . '" (' . $fcn . ')';
                            if ($log) {
                                $log->log($msg, 3);
                            } else {
                                error_log($msg);
                            }
                            continue;
                        }
                        $output = str_replace("{$calnl} ", '', rtrim($scomp->{$fcn}()));
                        $output = str_replace($propName . ';', '', $output);
                        $output = str_replace($propName . ':', '', $output);
                        $rows[$row][$proporder[$propName]] = fixiCalString($output);
                    }
                }
                // end foreach( $proporder
                if (isset($compinfo2['props']['X-PROP'])) {
                    while ($xprop = $scomp->getProperty()) {
                        $output = str_replace("{$calnl} ", '', rtrim($xprop[1]));
                        $rows[$row][$proporder[$xprop[0]]] = fixiCalString($output);
                    }
                }
            }
            // if( isset( $compinfo2['props']['X-PROP']
        }
        // end if( isset( $compinfo['sub']
    }
    // foreach( $compsinfo as
    if ($log) {
        $timeexec['compOk'] = microtime(TRUE);
    }
    /* fix csv format */
    // fields that contain commas, double-quotes, or line-breaks must be quoted,
    // a quote within a field must be escaped with an additional quote immediately preceding the literal quote,
    // space before and after delimiter commas may be trimmed (which is prohibited by RFC 4180)
    // a line break within an element must be preserved.
    // Fields may ALWAYS be enclosed within double-quote characters, whether necessary or not.
    foreach ($rows as $row => $line) {
        for ($col = 0; $col < $maxColCount; $col++) {
            if (!isset($line[$col]) || empty($line[$col])) {
                $rows[$row][$col] = $conf['del'] . $conf['del'];
                continue;
            }
            if (ctype_digit($line[$col])) {
                continue;
            }
            $cell = str_replace($conf['del'], $conf['del'] . $conf['del'], $line[$col]);
            $rows[$row][$col] = $conf['del'] . $cell . $conf['del'];
        }
        $rows[$row] = implode($conf['sep'], $rows[$row]);
    }
    $output = implode($conf['nl'], $rows) . $conf['nl'];
    if ($log) {
        $timeexec['exit'] = microtime(TRUE);
        $msg = "{$iCal2csv_VERSION} '{$filename}'";
        $msg .= ' fileOk:' . number_format($timeexec['fileOk'] - $timeexec['start'], 5);
        $msg .= ' infoOk:' . number_format($timeexec['infoOk'] - $timeexec['fileOk'], 5);
        $msg .= ' zoneOk:' . number_format($timeexec['zoneOk'] - $timeexec['infoOk'], 5);
        $msg .= ' compOk:' . number_format($timeexec['compOk'] - $timeexec['zoneOk'], 5);
        $msg .= ' csvOk:' . number_format($timeexec['exit'] - $timeexec['compOk'], 5);
        $msg .= ' total:' . number_format($timeexec['exit'] - $timeexec['start'], 5) . 'sec';
        $log->log($msg, 7);
        $msg = "{$iCal2csv_VERSION} '{$filename}' (" . count($compsinfo) . ' components) start:' . date('H:i:s', $timeexec['start']);
        $msg .= ' total:' . number_format($timeexec['exit'] - $timeexec['start'], 5) . 'sec';
        if ($save) {
            $msg .= " -> '{$diskfilename}'";
        }
        $msg .= ', size=' . strlen($output);
        $msg .= ', ' . count($rows) . " rows, {$maxColCount} cols";
        $log->log($msg, 6);
    }
    /* save or send the file */
    if ($save) {
        if (FALSE !== file_put_contents($diskfilename, $output)) {
            if ($log) {
                $log->flush();
            }
            return TRUE;
        } else {
            $msg = $iCal2csv_VERSION . ' ERROR 11 INPUT FILE:"' . $filename . '" Invalid write to output file : "' . $diskfilename . '"';
            if ($log) {
                $log->log($msg, 3);
                $log->flush();
            } else {
                error_log($msg);
            }
            return FALSE;
        }
    } else {
        if ($log) {
            $log->flush();
        }
        /** return data, auto gzip */
        $filezise = strlen($output);
        if (isset($_SERVER['HTTP_ACCEPT_ENCODING'])) {
            $output = gzencode($output, 9);
            $filezise = strlen($output);
            header('Content-Encoding: gzip');
            header('Vary: *');
        }
        header('Content-Type: text/csv; charset=utf-8');
        header('Content-Disposition: attachment; filename="' . $outputFileParts['basename'] . '"');
        header('Cache-Control: max-age=10');
        header('Content-Length: ' . $filezise);
        echo $output;
    }
    exit;
}
Esempio n. 6
0
$thumb = new ElggFile();
$thumb->setMimeType($_FILES['ical_file']['type']);
$thumb->setFilename($_FILES['ical_file']['name']);
$thumb->open('write');
$thumb->close();
// copy the file
$moved = move_uploaded_file($_FILES['ical_file']['tmp_name'], $thumb->getFilenameOnFilestore());
if (!$moved) {
    register_error(elgg_echo('event_calendar:file:cannotload'));
    forward(REFERER);
}
$path = pathinfo($thumb->getFilenameOnFilestore());
$config = array('unique_id' => elgg_get_site_url(), 'delimiter' => '/', 'directory' => $path['dirname'], 'filename' => $_FILES['ical_file']['name']);
$v = new vcalendar($config);
$v->parse();
$timezone_calendar = $v->getProperty('X-WR-TIMEZONE');
$export_timezone = false;
if ($timezone_calendar[1]) {
    $export_timezone = $timezone_calendar[1];
}
$event_calendar_times = elgg_get_plugin_setting('times', 'event_calendar');
$event_calendar_region_display = elgg_get_plugin_setting('region_display', 'event_calendar');
$event_calendar_type_display = elgg_get_plugin_setting('type_display', 'event_calendar');
$event_calendar_more_required = elgg_get_plugin_setting('more_required', 'event_calendar');
// for now, turn off the more_required setting during import
elgg_set_plugin_setting('more_required', 'no', 'event_calendar');
$created = array();
// an array to hold all of the created events
while ($vevent = $v->getComponent()) {
    if ($vevent instanceof vevent) {
        $dtstart = $vevent->getProperty('dtstart');