"", //date/time stamp "uid" => "", //unique id "tit" => "", //title "des" => "", //description "cat" => "", //category "ven" => "", //venue "pri" => 0, //private "sda" => "", //start date "eda" => "", //end date "sti" => "", //start time "eti" => "", //end time "r_t" => 0, //repeat type "r_i" => 0, //repeat interval "r_p" => 0, //repeat period "r_m" => 0, //repeat month "r_u" => "", //repeat until "tmz" => "" //timezone ); $hits = array(); $rrule = $valarm = false; //iterate icsLines for one event while (list($k, $v) = explode(':', str_replace('\;','~',$icsLines[$curLine++]), 2)) { //1st colon only $key = explode(';',$k); $value = explode(';',$v); foreach ($key as &$val) { $val = trim($val); } foreach ($value as &$val) { $val = trim($val); } unset($val); //break reference if ($key[0] == "END" and $value[0] == "VEVENT") { break; } //event end if ($key[0] == "BEGIN" and $value[0] == "VALARM") { $valarm = true; break; } //alarm begin if ($key[0] == "END" and $value[0] == "VALARM") { $valarm = false; break; } //alarm end if ($valarm) { break; } //skipping through alarm component switch (strtoupper($key[0])) { case "DTSTAMP": $event['dtS'] = $value[0]; break; case "UID": $event['uid'] = $value[0]; break; case "CLASS": if ($value[0] != "PUBLIC") { $event['pri'] = 1; } break; case "SUMMARY": $event['tit'] = $value[0]; break; case "DESCRIPTION": $event['des'] .= trim(stripslashes(str_ireplace(array('\n','~'),array("\n",';'),$value[0]))); //double quotes important! break; case "URL": $event['des'] .= "\nurl\n"; break; case "LOCATION": $event['ven'] = $value[0]; break; case "CATEGORIES": $event['cat'] = $value[0]; break; case "RRULE": $rrule = true; $r_i1 = $r_i2 = $r_p1 = $r_p2 = $r_count = $r_m = 0; $rUntil = ''; //init foreach ($value as &$val) { //process each individual value if (preg_match("%^FREQ=(DAILY|WEEKLY|MONTHLY|YEARLY)$%i", $val, $hits)) { $r_i1 = 1; switch (strtoupper($hits[1])) { case 'DAILY': $r_p1 = 1; break; case 'WEEKLY': $r_p1 = 2; break; case 'MONTHLY': $r_p1 = 3; break; case 'YEARLY': $r_p1 = 4; } } elseif (preg_match("%^INTERVAL=([1-6])$%i" , $val, $hits)) { $r_i1 = $hits[1]; } elseif (preg_match("%^BYMONTH=(\d|1[0-2])$%i" , $val, $hits)) { //only works if only 1 month $r_m = $hits[1]; } elseif (preg_match("%^BYDAY=([1-4]?|(?:-1)?)(MO|TU|WE|TH|FR|SA|SU)$%i", $val, $hits)) { $r_i2 = ($hits[1]) ? (($hits[1] != '-1') ? $hits[1] : '5') : '1'; //-1 => 5 (last x-day) switch (strtoupper($hits[2])) { case 'MO': $r_p2 = 1; break; case 'TU': $r_p2 = 2; break; case 'WE': $r_p2 = 3; break; case 'TH': $r_p2 = 4; break; case 'FR': $r_p2 = 5; break; case 'SA': $r_p2 = 6; break; case 'SU': $r_p2 = 7; } } elseif (preg_match("%^COUNT=([1-9][0-9]?)$%i", $val, $hits)) { $r_count = $hits[1]; } elseif (preg_match("%^UNTIL=(\d{8})(T.*)*$%i" , $val, $hits)) { $rUntil = substr($hits[1],0,4)."-".substr($hits[1],4,2)."-".substr($hits[1],6,2); } } break; case "DTSTART": if (preg_match("%^(\d{8})(T\d{4})?%i",$value[0],$hits)) { $event['sda'] = substr($hits[1],0,4)."-".substr($hits[1],4,2)."-".substr($hits[1],6,2); if (isset($hits[2])) { $event['sti'] = substr($hits[2],1,2).":".substr($hits[2],3,2); } if (substr($value[0],-1) == 'Z') { $event['tmz'] = 'UTC'; //UTC time } elseif (!empty($key[1]) and strtoupper(substr($key[1],0,5)) == 'TZID=') { $event['tmz'] = substr($key[1],5); } } break; case "DTEND": if (preg_match("%^(\d{8})(T\d{4})?%i",$value[0],$hits)) { $event['eda'] = substr($hits[1],0,4)."-".substr($hits[1],4,2)."-".substr($hits[1],6,2); if (isset($hits[2])) { $event['eti'] = substr($hits[2],1,2).":".substr($hits[2],3,2); } } break; case "DURATION": if (!isset($event['eda']) and !isset($event['eti'])) { if (preg_match("%^\+?P(?:(\d{1,2})W)?(?:(\d{1,2})D)?T(?:(\d{1,2})H)?(?:(\d{1,2})M)?%i", $value[0], $hits)) { $durSeconds = 604800*$hits[1] + 86400*$hits[2] + 3600*$hits[3] + 60*$hits[1]; $eUnixTS = strtotime($event['sda'].' '.$event['sti'].':00') + $durSeconds; $event['eda'] = date('Y-m-d',$eUnixTS); $event['eti'] = date('H:i',$eUnixTS); } } break; } } if (!$event['tmz']) { $event['tmz'] = $tZone; } //event timezone $validTZ = in_array($event['tmz'], timezone_identifiers_list()); //check if valid timezone if ($tzAdjust and $validTZ and $event['tmz'] != $set['timeZone']) { //adjust to timezone differences $curTZone = new DateTimeZone($set['timeZone']); $evtTZone = new DateTimeZone($event['tmz']); $dtNow = new DateTime("now"); $tzOffset = $curTZone->getOffset($dtNow) - $evtTZone->getOffset($dtNow); //offset $eUnixTS = strtotime($event['sda'].' '.$event['sti'].':00') + $tzOffset; $event['sda'] = date('Y-m-d',$eUnixTS); $event['sti'] = date('H:i',$eUnixTS); if ($event['eti']) { $eDate = $event['eda'] ? $event['eda'] : $event['sda']; $eUnixTS = strotime($eDate.' '.$event['eti'].':00') + $tzOffset; $event['eda'] = date('Y-m-d',$eUnixTS); $event['eti'] = date('H:i',$eUnixTS); } } /* validate event */ if (!$event['tit'] or !$event['sda']) { return false; } //error $event['des'] = trim($event['des']); //strip off newlines /* post processing */ //end date if ($event['eda'] > $event['sda'] and !$event['eti']) { $event['eda'] = date('Y-m-d',strtotime($event['eda']) - 86400); //-1 day } if ($event['eda'] == $event['sda']) { $event['eda'] = ''; }; //recurring events if ($rrule) { if (($r_p1 == 3 and $r_p2 > 0) or ($r_p1 == 4 and $r_p2 > 0 and $r_m > 0)) { //every xth (r_i) (0-5) (r_p) of the month y (r_m) $event['r_t'] = 2; $event['r_i'] = $r_i2; $event['r_p'] = $r_p2; $event['r_m'] = $r_m; if ($rUntil) { $event['r_u'] = $rUntil; } elseif ($r_count) { $r_count--; $event['r_u'] = date('Y-m-d', mktime (0,0,0,substr($event['sda'],5,2) + $r_count,substr($event['sda'],8,2),substr($event['sda'],0,4))); } } elseif ($r_i2 == 0 and $r_p1 > 0) { $event['r_t'] = 1; //every xth (0-6) day|week|month|year $event['r_i'] = $r_i1; $event['r_p'] = $r_p1; if ($rUntil) { $event['r_u'] = $rUntil; } elseif ($r_count) { $r_count--; $r_offd = $r_offm = $r_offy = 0; switch ($r_p1) { case 1: $r_offd = $r_i1 * $r_count; break; //daily case 2: $r_offd = $r_i1 * 7 * $r_count; break; //weekly case 3: $r_offm = $r_i1 * $r_count; break; //monthly case 4: $r_offy = $r_i1 * $r_count; //yearly } $event['r_u'] = date('Y-m-d',mktime(12,0,0,substr($event['sda'],5,2) + $r_offm,substr($event['sda'],8,2) + $r_offd,substr($event['sda'],0,4) + $r_offy)); } } else { $event['r_t'] = -1; //RRULE incompatible } } return $event; } function processEvtFields(&$sDate,&$eDate,&$sTime,&$eTime,&$title) { //validate event fields $errors = 0; $nofDates = count($sDate); for ($i = 0; $i < $nofDates; $i++) { $error = 0; if (($IsDate = DDtoID($sDate[$i])) === false) { $error++; } //convert Display Date to ISO Date if (($IeDate = DDtoID($eDate[$i])) === false) { $error++; } if (($IsTime = DTtoIT($sTime[$i])) === false) { $error++; } if (($IeTime = DTtoIT($eTime[$i])) === false) { $error++; } if (!$error) { if ($IsDate == $IeDate) { $IeDate = ''; } if ($IeDate and (!$IsDate or $IeDate < $IsDate)) { list($IsDate,$IeDate) = array($IeDate,$IsDate); } //swap start and end date if ($IeDate and !$IsTime and !$IeTime) { $IeDate = date("Y-m-d",strtotime($IeDate.' 12:00:00') - 86400); //-1 day if ($IsDate == $IeDate) { $IeDate = ''; } } if (!$IeDate and $IsTime == $IeTime) { $IeTime = ""; } if ($IeTime and !$IeDate and ($IeTime < $IsTime or !$IsTime)) { list($IsTime,$IeTime) = array($IeTime,$IsTime); } //swap start and end time $sDate[$i] = IDtoDD($IsDate); //convert ISO Date to Display Date $eDate[$i] = IDtoDD($IeDate); $sTime[$i] = ITtoDT($IsTime); //convert ISO Time to Display Time $eTime[$i] = ITtoDT($IeTime); } $errors += $error; if (!$title[$i]) { $errors++; } //title empty } return $errors; } function eventInDb($title,$sDate,$eDate,$sTime,$eTime) { //test if event present in db $q = "SELECT `title` FROM `events` e WHERE `status` >= 0 AND `title` = ? AND `sDate` = ? AND `eDate` = ? AND `sTime` = ? AND `eTime` = ? "; $stH = stPrep($q); stExec($stH,array($title,$sDate,$eDate,$sTime,$eTime)); $row = $stH->fetch(PDO::FETCH_ASSOC); $stH = null; return (!empty($row) ? true : false); } /* main functions */ function instructions() { global $ax; $stH = dbQuery("SELECT `ID`,`name` FROM `categories` WHERE `status` >= 0 ORDER BY `ID`"); echo "\n"; } function uploadFile() { global $ax, $defcatID, $tzAdjust, $fromD, $lcI; echo "
{$ax['iex_upload_ics']}\n
{$ax['iex_file']}:
{$ax['iex_default_cat_id']}: ({$ax['iex_if_no_cat']})
{$ax['iex_tz_adjust']}:
{$ax['iex_import_events_from_date']}: 📅
\n"; } function processUpload() { global $ax, $curLine, $defcatID, $tZone, $fromID; $calProps = array("PRODID","VERSION","TZID","X-WR-CALNAME","X-LC-CONTENT"); //iCal properties and components of interest $fName = $_FILES['fName']['tmp_name']; if (!$fName) { return $ax['iex_no_file_name']; } //ical file missing $fContent = file_get_contents($fName); //read file unlink($fName); $begin = strpos($fContent,'BEGIN:VCALENDAR'); if ($begin === false) { return $ax['iex_no_begin_tag']; } //sanity check $fContent = preg_replace("#\r?\n[\s\t]#m","",trim(substr($fContent,$begin+15))); //skip BEGIN and unfold lines $icsLines = preg_split("#\r?\n#", $fContent); //split into lines unset($fContent); //Get calendar categories $cats = array(); $stH = dbQuery("SELECT `ID`,`name` FROM `categories` WHERE `status` >= 0 ORDER BY `ID`"); while ($row = $stH->fetch(PDO::FETCH_ASSOC)) { $cats[$row['name']] = $row['ID']; } //Iterate icsLines $curLine = 1; while (isset($icsLines[$curLine])) { list($key, $value) = explode(':', $icsLines[$curLine++], 2); $key = strtoupper(trim($key)); $value = trim($value); if ($key == "BEGIN" and strtoupper($value) == "VEVENT") { //event start $event = parseEvent($icsLines); if ($event === false) { return $ax['iex_ics_file_error_on_line'].": ".$curLine; } //ics file error //save event data if (($event['r_t'] == 0 and ($event['sda'] >= $fromID or $event['eda'] >= $fromID)) or ($event['r_t'] != 0 and (!$event['r_u'] or $event['r_u'] >= $fromID))) { $curCat = ''; foreach ($cats as $catName => $catID) { if (strpos(strtolower($event['cat']), trim(strtolower($catName))) !== false) { $curCat = $catID; break; } } $_POST['title'][] = $event['tit']; $_POST['venue'][] = $event['ven']; $_POST['descr'][] = $event['des']; $_POST['catID'][] = ($curCat) ? $curCat : $defcatID; $_POST['sDate'][] = IDtoDD($event['sda']); $_POST['eDate'][] = IDtoDD($event['eda']); if ($event['sti'] == '00:00' and $event['eti'] == '23:59') { //all day $event['sti'] = $event['eti'] = ''; } $_POST['sTime'][] = ITtoDT($event['sti']); $_POST['eTime'][] = ITtoDT($event['eti']); $_POST['r_t'][] = $event['r_t']; $_POST['r_i'][] = $event['r_i']; $_POST['r_p'][] = $event['r_p']; $_POST['r_m'][] = $event['r_m']; $_POST['r_u'][] = IDtoDD($event['r_u']); $_POST['delete'][] = 0; } } else { //meta data if (in_array($key, $calProps)) { if ($key == 'TZID') { $tZone = $value; } //set global time zone $_POST[$key] = $value; //save meta data } } } return ''; //no error } function displayEvents($errors) { global $ax, $defcatID, $tzAdjust, $fromD, $fromID, $lcI; $nofEvents = count($_POST['title']); if ($nofEvents == 0) { //no events echo "
{$ax['iex_no_events_from_date']} ".IDtoDD($fromID)."

\n"; return; } $listHead = ""; echo "

{$ax['iex_number_of_errors']}: {$errors} ({$ax['iex_bgnd_highlighted']})


{$ax['iex_verify_event_list']} \"{$ax['iex_add_events']}\"


{$ax['iex_select_ignore']}

\n"; echo "\n"; //display event list echo "
\n"; if (!empty($_POST['X-WR-CALNAME'])) { $listHead .= $_POST['X-WR-CALNAME']; echo "\n"; } if (!empty($_POST['X-LC-CONTENT'])) { $listHead .= "   ({$_POST['X-LC-CONTENT']})"; echo "\n"; } echo "\n"; if ($listHead) { echo "\n"; } echo "\n"; for ($i = 0; $i < $nofEvents; $i++) { $tic = (!$_POST['title'][$i]) ? " class='inputError'" : ''; $sdc = (DDtoID($_POST['sDate'][$i]) === false) ? ' class="inputError"' : ''; $edc = (($_POST['eDate'][$i]) and (DDtoID($_POST['eDate'][$i]) === false)) ? ' class="inputError"' : ''; $stc = (DTtoIT($_POST['sTime'][$i]) === false) ? ' class="inputError"' : ''; $etc = (($_POST['eTime'][$i]) and (DTtoIT($_POST['eTime'][$i]) === false)) ? ' class="inputError"' : ''; $nr = $i+1; echo "\n"; // echo '\n"; //for testing echo "\n"; } echo "

{$listHead}

#{$ax['iex_ignore']}{$ax['iex_title']}{$ax['iex_venue']}{$ax['iex_category']}{$ax['iex_date']}{$ax['iex_end_date']}{$ax['iex_start_time']}{$ax['iex_end_time']}{$ax['iex_description']}{$ax['iex_repeat']}
{$nr} ".repeatText($_POST['r_t'][$i],$_POST['r_i'][$i],$_POST['r_p'][$i],$_POST['r_m'][$i],DDtoID($_POST['r_u'][$i]))."r_t= '.$_POST['r_t'][$i].' r_i= '.$_POST['r_i'][$i].' r_p= '.$_POST['r_p'][$i].'
r_m= '.$_POST['r_m'][$i].' r_u= '.$_POST['r_u'][$i]."

\n"; } function addEvents() { global $usr, $ax, $defcatID; $msg = ""; $nofEvents = count($_POST['title']); $added = $dropped = 0; for ($i = 0; $i < $nofEvents; $i++) { if (empty($_POST['delete'][$i]) and $_POST['r_t'][$i] >= 0) { //if delete not ticked and repeat-type is valid $title = htmlspecialchars_decode(trim($_POST['title'][$i])); $venue = htmlspecialchars_decode(trim($_POST['venue'][$i])); $descr = strip_tags(trim($_POST['descr'][$i]),''); $descr = addUrlImgEmlTags($descr,'x--'); //add URL link tags $descr = str_ireplace(array("\r\n", "\n", "\r"),"
",$descr); //allow URLs and replace newline by
$sDate = DDtoID($_POST['sDate'][$i]); $eDate = ($_POST['eDate'][$i]) ? DDtoID($_POST['eDate'][$i]) : "9999-00-00"; $sTime = DTtoIT($_POST['sTime'][$i]); $eTime = ($_POST['eTime'][$i]) ? DTtoIT($_POST['eTime'][$i]) : "99:00:00"; if (empty($sTime)) { //all day $sTime = '00:00'; $eTime = '23:59'; } $r_t = $_POST['r_t'][$i]; $r_i = $_POST['r_i'][$i]; $r_p = $_POST['r_p'][$i]; $r_m = $_POST['r_m'][$i]; $r_u = ($_POST['r_u'][$i]) ? DDtoID($_POST['r_u'][$i]) : "9999-00-00"; $catID = ($_POST['catID'][$i]) ? $_POST['catID'][$i] : 1; //no cat if (!eventInDb($title,$sDate,$eDate,$sTime,$eTime)) { //add event to db $q = "INSERT INTO `events` (`title`,`venue`,`text1`,`catID`,`userID`,`sDate`,`eDate`,`sTime`,`eTime`,`rType`,`rInterval`,`rPeriod`,`rMonth`,`rUntil`,`aDateTime`,`mDateTime`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; $stH = stPrep($q); stExec($stH,array($title,$venue,$descr,$catID,$usr['ID'],$sDate,$eDate,$sTime,$eTime,$r_t,$r_i,$r_p,$r_m,$r_u,date("Y-m-d H:i"),date("Y-m-d H:i"))); $added++; } else { $dropped++; } } } if (!$msg) $msg = $added." ".$ax['iex_events_added'].($dropped > 0 ? " / {$dropped} {$ax['iex_events_dropped']}" : ""); return $msg; } //control logic $msg = ""; $errors = 0; //init if ($usr['privs'] == 9) { //admin if (isset($_POST['uploadFile'])) { if (!$fromID) { $msg = $ax['iex_bad_date']; //invalid date } else { $msg = processUpload(); } } if ((isset($_POST['uploadFile']) and !$msg) or isset($_POST['addEvents'])) { $errors = processEvtFields($_POST['sDate'],$_POST['eDate'],$_POST['sTime'],$_POST['eTime'],$_POST['title']); } if (isset($_POST['addEvents']) and !$errors) { $msg = addEvents(); //add events to calendar } echo "

{$msg}

\n"; if (!isset($_POST['uploadFile']) and !isset($_POST['addEvents']) or (isset($_POST['uploadFile']) and $msg)) { instructions(); } echo "
\n"; if (!isset($_POST['uploadFile']) and !isset($_POST['addEvents']) or (isset($_POST['uploadFile']) and $msg)) { uploadFile(); } elseif (!isset($_POST['addEvents']) or $errors) { displayEvents($errors); //file uploaded or errors, display events } else { echo "\n"; } echo "
\n
\n"; } else { echo "

{$ax['no_way']}

\n"; } ?>