/** * 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; }
/** * 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); }
/** * 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; }
$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');