<?php /** * JEvents Component for Joomla! 3.x * * @version $Id: iCalImport.php 3467 2012-04-03 09:36:16Z geraintedwards $ * @package JEvents * @copyright Copyright (C) 2008-2019 GWE Systems Ltd, 2006-2008 JEvents Project Group * @license GNU/GPLv2, see http://www.gnu.org/licenses/gpl-2.0.html * @link http://www.jevents.net */ // no direct access defined( '_JEXEC' ) or die( 'Restricted access' ); use Joomla\String\StringHelper; // This class doesn't yet deal with repeating events class iCalImport { /** * This array saves the iCalendar parsed data as an array - may make a class later! * * @var array */ var $cal = array(); var $key; var $rawData = ''; var $srcURL = ''; var $eventCount = -1; var $todoCount = -1; var $vevents = array(); function __construct () { } // constructor function import($filename,$rawtext="") { @ini_set("max_execution_time",600); echo JText::sprintf("Importing events from ical file %s", $filename)."<br/>"; $cfg = JEVConfig::getInstance(); $option = JEV_COM_COMPONENT; // resultant data goes here if ($filename!=""){ $file = $filename; if (!@file_exists($file)) { $file = JPATH_SITE."/components/$option/".$filename; } if (!file_exists($file)) { echo "I hope this is a URL!!<br/>"; $file = $filename; } // get name $isFile = false; if (isset($_FILES['upload']) && is_array($_FILES['upload']) ) { $uploadfile = $_FILES['upload']; // MSIE sets a mime-type of application/octet-stream if ($uploadfile['size']!=0 && ($uploadfile['type']=="text/calendar" || $uploadfile['type']=="text/csv" || $uploadfile['type']=="application/octet-stream" || $uploadfile['type']=="text/html")){ $this->srcURL = $uploadfile['name']; $isFile = true; } } if ($this->srcURL =="") { $this->srcURL = $file; } // $this->rawData = iconv("ISO-8859-1","UTF-8",file_get_contents($file)); if (!$isFile && is_callable("curl_exec")){ $ch = curl_init(); // Set curl option CURLOPT_HTTPAUTH, if the url includes user name and password. // e.g. http://username:password@www.example.com/cal.ics $username = parse_url($file, PHP_URL_USER); $password = parse_url($file, PHP_URL_PASS); if ($username != "" && $password != "") { curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); } // Set proxy if enabled $jConfig = JFactory::getConfig(); if($jConfig->get('proxy_enable') == 1) { curl_setopt($ch, CURLOPT_PROXY, $jConfig->get('proxy_host') . ":" . $jConfig->get('proxy_port')); curl_setopt($ch, CURLOPT_PROXYUSERPWD, $jConfig->get('proxy_user') . ":" . $jConfig->get('proxy_password')); } curl_setopt($ch, CURLOPT_URL, $file); curl_setopt($ch, CURLOPT_VERBOSE, 1); curl_setopt($ch, CURLOPT_POST, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_USERAGENT, "Jevents.net"); curl_setopt($ch,CURLOPT_ENCODING,''); $this->rawData = curl_exec($ch); curl_close ($ch); // try file_get_contents as a backup if ($this->rawData === false || $this->rawData == "") { $this->rawData = @file_get_contents($file); } } else { $this->rawData = @file_get_contents($file); } if ($this->rawData === false) { // file_get_contents: no or blocked wrapper for $file JError::raiseNotice(0, 'file_get_contents() failed, try fsockopen'); $parsed_url = parse_url($file); if ($parsed_url === false) { JError::raiseWarning(0, 'url not parsed: ' . $file); } else { if ($parsed_url['scheme'] == 'http' || $parsed_url['scheme'] == 'https' || $parsed_url['scheme'] == 'webcal') { // try socked connection $fsockhost = $parsed_url['host']; $fsockport = 80; if ($parsed_url['scheme'] == 'https') { $fsockhost = 'ssl://' . $fsockhost; $fsockport = 443; } if (array_key_exists('port', $parsed_url)) $fsockport = $parsed_url['port']; $fh = @fsockopen($fsockhost, $fsockport, $errno, $errstr, 3); if ($fh === false) { // fsockopen: no connect JError::raiseWarning(0, 'fsockopen: no connect for ' . $file.' - '.$errstr ); return false; } else { $fsock_path = ((array_key_exists('path', $parsed_url)) ? $parsed_url['path'] : '') . ((array_key_exists('query', $parsed_url)) ? '?' . $parsed_url['query'] : '') . ((array_key_exists('fragment', $parsed_url)) ? '#' . $parsed_url['fragment'] : ''); fputs($fh, "GET $fsock_path HTTP/1.0\r\n"); fputs($fh, "Host: ".$parsed_url['host']."\r\n\r\n"); while(!feof($fh)) { $this->rawData .= fread($fh,4096); } fclose($fh); $this->rawData = JString::substr($this->rawData, JString::strpos($this->rawData, "\r\n\r\n")+4); } } } } // Returns true if $string is valid UTF-8 and false otherwise. /* $isutf8 = $this->detectUTF8($this->rawData); if ($isutf8) { $this->rawData = iconv("ISO-8859-1","UTF-8",$this->rawData); } */ } else { $this->srcURL="n/a"; $this->rawData = $rawtext; } ; // get rid of spurious carriage returns and spaces //$this->rawData = preg_replace("/[\r\n]+ ([:;])/","$1",$this->rawData); // simplify line feed $this->rawData = str_replace("\r\n","\n",trim($this->rawData)); // remove spurious lines before calendar start if (!JString::stristr($this->rawData,'BEGIN:VCALENDAR')) { JFactory::getApplication()->triggerEvent('onImportCsvFile', array(& $this->rawData)); // check for CSV format $firstLine = JString::substr($this->rawData,0,JString::strpos($this->rawData,"\n")+1); if (JString::stristr($firstLine,'SUMMARY') && JString::stristr($firstLine,'DTSTART') && JString::stristr($firstLine,'DTEND') && JString::stristr($firstLine,'CATEGORIES') && JString::stristr($firstLine,'TIMEZONE')) { $timezone= date_default_timezone_get(); $csvTrans = new CsvToiCal($file, ",",$this->rawData); $this->rawData = $csvTrans->getRawData(); date_default_timezone_set($timezone); } else { //echo "first line = $firstLine<br/>"; //echo "raw imported data = ".$this->rawData."<br/>"; //exit(); if (JFactory::getUser()->get('isRoot') && JFactory::getApplication()->isAdmin()) { $config = JFactory::getConfig(); $debug = (boolean) $config->get('debug'); if ($debug){ echo "Unable to fetch calendar data<br/>"; echo "Raw Data is ".$this->rawData; exit(); } } JError::raiseWarning(0, 'Not a valid VCALENDAR data file: ' . $this->srcURL); //JError::raiseWarning(0, 'Not a valid VCALENDAR or CSV data file: ' . $this->srcURL); // return false so that we don't remove a valid calendar because of a bad URL load! return false; } } $begin = JString::strpos($this->rawData,"BEGIN:VCALENDAR",0); $this->rawData = JString::substr($this->rawData,$begin); // $this->rawData = preg_replace('/^.*\n(BEGIN:VCALENDAR)/s', '$1', $this->rawData, 1); // unfold content lines according the unfolding procedure of rfc2445 $this->rawData = str_replace("\n ","",$this->rawData); $this->rawData = str_replace("\n\t","",$this->rawData); // TODO make sure I can always ignore the second line // Some google calendars has spaces and carriage returns in their UIDs // Convert string into array for easier processing $this->rawData = explode("\n", $this->rawData); $skipuntil = null; foreach ($this->rawData as $vcLine) { //$vcLine = trim($vcLine); // trim one line if (empty($vcLine)){ continue; } if (!empty($vcLine)) { // skip unhandled block if ($skipuntil) { if (trim($vcLine) == $skipuntil) { // found end of block to skip $skipuntil = null; } continue; } $matches = explode(":",$vcLine,3); // Catch some bad Microsoft timezones e.g. "(UTC+01:00) Amsterdam, Berlin, Bern, Rom, Stockholm, Wien" if (count($matches) == 3) { if (strpos($matches[0], ";TZID")>0){ $matches[0] = $matches[0].":".$matches[1]; $matches[1] = $matches[2]; unset($matches[2]); } else { $matches = explode(":",$vcLine,2); } } if (count($matches) == 2) { list($this->key,$value)= $matches; //$value = str_replace('\n', "\n", $value); //$value = stripslashes($value); $append=false; // Treat Accordingly switch ($vcLine) { case "BEGIN:VTODO": // start of VTODO section $this->todoCount++; $parent = "VTODO"; break; case "BEGIN:VEVENT": // start of VEVENT section $this->eventCount++; $parent = "VEVENT"; break; case "BEGIN:VCALENDAR": case "BEGIN:DAYLIGHT": case "BEGIN:VTIMEZONE": case "BEGIN:STANDARD": $parent = $value; // save tu array under value key break; case "END:VTODO": case "END:VEVENT": case "END:VCALENDAR": case "END:DAYLIGHT": case "END:VTIMEZONE": case "END:STANDARD": $parent = "VCALENDAR"; break; default: // skip unknown BEGIN/END blocks if ($this->key == 'BEGIN') { $skipuntil = 'END:' . $value; break; } // Generic processing $this->add_to_cal($parent, $this->key, $value,$append); break; } } else { // ignore these lines go } } } // Sort the events into start date order // there's little point in doing this id an RRULE is present! // usort($this->cal['VEVENT'], array("iCalImport","comparedates")); // Populate vevent class - should do this first trawl through !! if (array_key_exists("VEVENT",$this->cal)) { foreach ($this->cal["VEVENT"] as $vevent){ // trap for badly constructed all day events if (isset($vevent["DTSTARTRAW"]) && isset($vevent["DTENDRAW"]) && $vevent["DTENDRAW"] == $vevent["DTSTARTRAW"]){ //$vevent["DTEND"] += 86400; $vevent["NOENDTIME"] = 1; } // some imports do not have UID set if (!isset($vevent["UID"])){ $vevent["UID"] = md5(uniqid(rand(), true)); } $this->vevents[] = iCalEvent::iCalEventFromData($vevent); } } //exit(0); return $this; } function add_to_cal($parent, $key, $value, $append) { $params = JComponentHelper::getParams(JEV_COM_COMPONENT); // I'm not interested in when the events were created/modified if (($key == "DTSTAMP") or ($key == "LAST-MODIFIED") or ($key == "CREATED")) return; if ($key == "RRULE" && $value!="") { $value = $this->parseRRULE($value,$parent); } $rawkey=""; if (JString::stristr($key,"DTSTART") || JString::stristr($key,"DTEND") || JString::stristr($key,"EXDATE") ) { list($key,$value,$rawkey,$rawvalue) = $this->handleDate($key,$value); // if midnight then move back one day (ISO 8601 uses seconds past midnight http://www.iso.org/iso/date_and_time_format) // because of the odd way we record midnights if (JString::stristr($key,"DTEND") == "DTEND" && JString::strlen($rawvalue)>=15 && JString::substr($rawvalue,9,6)=="000000") { $value -= 1; // 1 second //$value -= 86400; // 1 day } if (JString::stristr($key,"DTEND") == "DTEND" && JString::strlen($rawvalue) == 8) { // all day event detected YYYYMMDD, set DTEND to last second of previous day /* see section 3.6.1 of RFC https://tools.ietf.org/html/rfc5545 * The following is an example of the "VEVENT" calendar component used to represent a multi-day event scheduled from June 28th, 2007 to July 8th, 2007 inclusively. Note that the "DTEND" property is set to July 9th, 2007, since the "DTEND" property specifies the non-inclusive end of the event. BEGIN:VEVENT UID:20070423T123432Z-541111@example.com DTSTAMP:20070423T123432Z DTSTART;VALUE=DATE:20070628 DTEND;VALUE=DATE:20070709 SUMMARY:Festival International de Jazz de Montreal TRANSP:TRANSPARENT END:VEVENT */ $value -= 1; // 1 second } } if (JString::stristr($key,"DURATION")) { list($key,$value,$rawkey,$rawvalue) = $this->handleDuration($key,$value); } switch ($parent) { case "VTODO": $this->cal[$parent][$this->todoCount][$key] = $value; break; case "VEVENT": // strip off unnecessary quoted printable encoding message $parts = explode(';',$key); if (count($parts)>1 ){ $key=$parts[0]; for ($i=1; $i<count($parts);$i++) { if ($parts[$i]=="ENCODING=QUOTED-PRINTABLE"){ //$value=str_replace("=0D=0A","<br/>",$value); $value=quoted_printable_decode($value); } // drop other ibts like language etc. } } // Special treatment of if($key=="ATTACH") { $this->cal[$parent][$this->eventCount][$key][] = $value; } elseif (JString::strpos($key,"EXDATE")===false){ $target =& $this->cal[$parent][$this->eventCount][$key]; $rawtarget =& $this->cal[$parent][$this->eventCount][$rawkey]; } else { if (!array_key_exists("EXDATE",$this->cal[$parent][$this->eventCount])){ $this->cal[$parent][$this->eventCount]["EXDATE"]=array(); $this->cal[$parent][$this->eventCount]["RAWEXDATE"]=array(); } if (is_array($value)){ $this->cal[$parent][$this->eventCount]["EXDATE"] = array_merge($this->cal[$parent][$this->eventCount]["EXDATE"], $value); $this->cal[$parent][$this->eventCount]["RAWEXDATE"][count($this->cal[$parent][$this->eventCount]["RAWEXDATE"])] = $rawvalue; break; } else { $target =& $this->cal[$parent][$this->eventCount]["EXDATE"][count($this->cal[$parent][$this->eventCount]["EXDATE"])]; $rawtarget =& $this->cal[$parent][$this->eventCount]["RAWEXDATE"][count($this->cal[$parent][$this->eventCount]["RAWEXDATE"])]; } } // Remove escaping of text $value = str_replace('\,',',',$value); $value = str_replace('\;',';',$value); // convert URLs to links but NOT in uid field!! //$value = ereg_replace("[[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/]","<a href=\"\\0\">\\0</a>", $value); //$value = preg_replace('@(?<![">])\b(?:(?:https?|ftp)://|www\.|ftp\.)[-A-Z0-9+&@#/%=~_|$?!:,.]*[A-Z0-9+&@#/%=~_|$]@',"<a href=\"\\0\">\\0</a>", $value); // See http://stackoverflow.com/questions/8414675/preg-replace-for-url-and-download-links and http://regexr.com/3bup3 to test this //$value = preg_replace('@(https?://([\w-.]+)+(:\d+)?(/([\w/_\.%\-+~=]*(\?\S+)?)?)?)@u', '<a href="$1">$1</a>', $value); // See https://gist.github.com/winzig/8894715 //$value = preg_replace('@(https?:\/{1,3})?((?:(?:[\w.\-]+\.(?:[a-z]{2,13})|(?<=http:\/\/|https:\/\/)[\w.\-]+)\/)(?:[^\s()<>{}\[\]]+|\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\))+(?:\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\)|[^\s`!()\[\]{};:\'\".,<>?«»“”‘’])|(?:(?<!@)(?:\w+(?:[.\-]+\w+)*\.(?:[a-z]{2,13})|(?:(?:[0-9](?!\d)|[1-9][0-9](?!\d)|1[0-9]{2}(?!\d)|2[0-4][0-9](?!\d)|25[0-5](?!\d))[.]?){4})\b\/?(?!@)(?:[^\s()<>{}\[\]]+|\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\))*(?:\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\)|[^\s`!()\[\]{};:\'\".,<>?«»“”‘’])?))@gi', '<a href="$1$2">$1</a>', $value); if ($params->get("converturlstolinksonimport", 1) && is_string($value) && $key!="UID" && $key!="X-EXTRAINFO"){ if (JString::strpos(str_replace(" ","",JString::strtolower($value)),"<ahref=")===false && JString::strpos(str_replace(" ","",JString::strtolower($value)),"<img")===false && (JString::strpos(JString::strtolower($value),"http://")!==false || JString::strpos(JString::strtolower($value),"https://")!==false)){ // See http://stackoverflow.com/questions/8414675/preg-replace-for-url-and-download-links and http://regexr.com/3bup3 to test this $value = preg_replace('@(https?://([\w\-.]+)+(:\d+)?(/([\w/_\.%\-+~=]*(\?\S+)?)?)?)@u', '<a href="$1">$1</a>', $value); } } // Fix some stupid Microsoft IIS driven calendars which don't encode the data properly! // see section 2 of http://www.the-art-of-web.com/html/character-codes/ if ($key=="DESCRIPTION" || $key=="SUMMARY"){ $len = strlen($value); $ulen = JString::strlen($value); // Can cause problems with multibyte strings so skip this // we need to check this since some UTF-8 characters from Google get truncates otherwise if ($len == $ulen){ $value =str_replace(array("\205","\221","\222","\223","\224","\225","\226","\227","\240"),array("...","'","'",'"','"',"*","-","--"," "),$value); } } // Strip http:// from UID !!! if ($key=="UID" && JString::strpos($value,"http://")!==false){ $value = str_replace('http://',"http",$value); } if ($key=="RECURRENCE-ID"){ if (count($parts)>1 ){ for ($i=1; $i<count($parts);$i++) { if (JString::stristr($parts[$i],"TZID")){ $value = $parts[$i].";".$value; } } } } // THIS IS NEEDED BECAUSE OF DODGY carriage returns in google calendar UID // TODO check its enough if ($append){ $target .= $value; } else { $target = $value; } if ($rawkey!=""){ $rawtarget = $rawvalue; } break; default: $this->cal[$parent][$key] = $value; break; } } function parseRRULE($value, $parent) { $result = array(); $parts = explode(';',$value); foreach ($parts as $part) { if (JString::strlen($part)==0) continue; $portion = explode('=', $part); if (JString::stristr($portion[0],"UNTIL")){ $untilArray = $this->handleDate($portion[0],$portion[1]); $result[$untilArray[0]] = $untilArray[1]; $result[$untilArray[2]] = $untilArray[3]; } else $result[$portion[0]] = $portion[1]; } return $result; } /** * iCal spec represents date in ISO 8601 format followed by "T" then the time * a "Z at the end means the time is UTC and not local time zone * * TODO make sure if time is UTC we take account of system time offset properly * */ function unixTime($ical_date, $tz=false) { jimport("joomla.utilities.date"); static $offset = null; if (is_null($offset)) { $config = JFactory::getConfig(); $offset = $config->get('config.offset', 0); } if (!is_numeric($ical_date)){ $t = JevDate::strtotime($ical_date); if (JString::strpos($ical_date,"Z")>0){ if (is_callable("date_default_timezone_set")){ $timezone= date_default_timezone_get(); // See http://www.php.net/manual/en/timezones.php $params = JComponentHelper::getParams(JEV_COM_COMPONENT); // server offset tiemzone if ($params->get("icaltimezone","")!=""){ date_default_timezone_set($params->get("icaltimezone","")); } // server offset PARAMS $serveroffset1 = (JevDate::strtotime(JevDate::strftime('%Y%m%dT%H%M%S',$t))-JevDate::strtotime(JevDate::strftime('%Y%m%dT%H%M%SZ',$t)))/3600; // server offset SERVER date_default_timezone_set($timezone); $serveroffset2 = (JevDate::strtotime(JevDate::strftime('%Y%m%dT%H%M%S',$t))-JevDate::strtotime(JevDate::strftime('%Y%m%dT%H%M%SZ',$t)))/3600; $t = new JevDate($ical_date,($serveroffset1-$serveroffset2) ); //$t = new JevDate($ical_date ); date_default_timezone_set($timezone); echo "icaldate = ".$ical_date." imported date=".$t->toMySQL()."<br/>"; } else { // Summer Time adjustment list($y,$m,$d,$h,$min,$s) = explode(":", JevDate::strftime('%Y:%m:%d:%H:%M:%S',$t)); $dst = (JevDate::mktime($h,$min,$s,$m,$d,$y,0)-JevDate::mktime($h,$min,$s,$m,$d,$y,-1))/3600; // server offset including DST $serveroffset = (JevDate::strtotime(JevDate::strftime('%Y%m%dT%H%M%S',$t))-JevDate::strtotime(JevDate::strftime('%Y%m%dT%H%M%SZ',$t)))/3600; $serveroffset += $dst; $t = new JevDate($ical_date , -($serveroffset+$offset)); } /* echo "<h3>SET TIMEZONE</h3>"; $timezone= date_default_timezone_get(); date_default_timezone_set('America/New_York'); $tempIcal = "20091020T163000Z"; echo $tempIcal."<br/>"; $temp = JevDate::strtotime($tempIcal); list($y,$m,$d,$h,$min,$s) = explode(":", JevDate::strftime('%Y:%m:%d:%H:%M:%S',$temp)); echo "$y,$m,$d,$h,$min,$s<br/>"; $dst = (JevDate::mktime($h,$min,$s,$m,$d,$y,0)-JevDate::mktime($h,$min,$s,$m,$d,$y,-1))/3600; $so = (JevDate::strtotime(JevDate::strftime('%Y%m%dT%H%M%S',$temp))-JevDate::strtotime(JevDate::strftime('%Y%m%dT%H%M%SZ',$temp)))/3600; echo " dst=".$dst." serverforoffset=".$so."<br/>"; $so += $dst; $t = new JevDate($tempIcal); echo $t->toMySQL()."<br><br/>"; $tempIcal = "20091029T163000Z"; echo $tempIcal."<br/>"; $temp = JevDate::strtotime($tempIcal); list($y,$m,$d,$h,$min,$s) = explode(":", JevDate::strftime('%Y:%m:%d:%H:%M:%S',$temp)); echo "$y,$m,$d,$h,$min,$s<br/>"; $dst = (JevDate::mktime($h,$min,$s,$m,$d,$y,0)-JevDate::mktime($h,$min,$s,$m,$d,$y,-1))/3600; $so = (JevDate::strtotime(JevDate::strftime('%Y%m%dT%H%M%S',$temp))-JevDate::strtotime(JevDate::strftime('%Y%m%dT%H%M%SZ',$temp)))/3600; echo " dst=".$dst." serverforoffset=".$so."<br/>"; $so += $dst; $t = new JevDate($tempIcal ); echo $t->toMySQL()."<br><br/>"; $tempIcal = "20091103T163000Z"; echo $tempIcal."<br/>"; $temp = JevDate::strtotime($tempIcal); list($y,$m,$d,$h,$min,$s) = explode(":", JevDate::strftime('%Y:%m:%d:%H:%M:%S',$temp)); echo "$y,$m,$d,$h,$min,$s<br/>"; $dst = (JevDate::mktime($h,$min,$s,$m,$d,$y,0)-JevDate::mktime($h,$min,$s,$m,$d,$y,-1))/3600; $so = (JevDate::strtotime(JevDate::strftime('%Y%m%dT%H%M%S',$temp))-JevDate::strtotime(JevDate::strftime('%Y%m%dT%H%M%SZ',$temp)))/3600; echo " dst=".$dst." serverforoffset=".$so."<br/>"; $so += $dst; $t = new JevDate($tempIcal); echo $t->toMySQL()."<br>"; */ } else if ($tz != false && $tz != ""){ // really should use the timezone of the inputted date $tz = new DateTimeZone($tz); $t = new JevDate($ical_date, $tz); echo "icaldate = ".$ical_date." imported date=".$t->toMySQL()."<br/>"; } else { $compparams = JComponentHelper::getParams(JEV_COM_COMPONENT); $jtz = $compparams->get("icaltimezonelive", ""); if ($jtz){ $t = new JevDate($ical_date,$jtz); } else { $t = new JevDate($ical_date); } } //$result = $t->toMySQL(); $result = $t->toUnix(); return $result; } $isUTC = false; if (JString::strpos($ical_date,"Z")!== false){ $isUTC = true; } // strip "T" and "Z" from the string $ical_date = str_replace('T', '', $ical_date); $ical_date = str_replace('Z', '', $ical_date); // split it out intyo YYYY MM DD HH MM SS preg_match("#([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{0,2})([0-9]{0,2})([0-9]{0,2})#", $ical_date,$date); list($temp,$y,$m,$d,$h,$min,$s)=$date; if (!$min) $min=0; if (!$h) $h=0; if (!$d) $d=0; if (!$s) $s=0; // Trap unix dated beofre 1970 $y = max($y,1970); if ($isUTC) { $t = gmJevDate::mktime($h,$min,$s,$m,$d,$y) + 3600 * $offset; $result = JevDate::strtotime(gmdate('Y-m-d H:i:s', $t)); } else { $result = JevDate::mktime($h,$min,$s,$m,$d,$y); } // double check!! //list($y1,$m1,$d1,$h1,$min1,$s1)=explode(":",JevDate::strftime('%Y:%m:%d:%H:%M:%S',$result)); return $result; } // function to convert windows timezone IDs into Olsen equivalent public static function convertWindowsTzid($wtzid){ $wtzdata = array(); $wtzdata["Midway Island, Samoa"] = "Pacific/Midway"; $wtzdata["Hawaii-Aleutian"] = "America/Adak"; $wtzdata["Hawaii"] = "Etc/GMT+10"; $wtzdata["Marquesas Islands"] = "Pacific/Marquesas"; $wtzdata["Gambier Islands"] = "Pacific/Gambier"; $wtzdata["Alaska"] = "America/Anchorage"; $wtzdata["Tijuana, Baja California"] = "America/Ensenada"; $wtzdata["Pitcairn Islands"] = "Etc/GMT+8"; $wtzdata["Pacific Time (US & Canada)"] = "America/Los_Angeles"; $wtzdata["Mountain Time (US & Canada)"] = "America/Denver"; $wtzdata["Chihuahua, La Paz, Mazatlan"] = "America/Chihuahua"; $wtzdata["Arizona"] = "America/Dawson_Creek"; $wtzdata["Saskatchewan, Central America"] = "America/Belize"; $wtzdata["Guadalajara, Mexico City, Monterrey"] = "America/Cancun"; $wtzdata["Easter Island"] = "Chile/EasterIsland"; $wtzdata["Central Time (US & Canada)"] = "America/Chicago"; $wtzdata["Eastern Time (US & Canada)"] = "America/New_York"; $wtzdata["Cuba"] = "America/Havana"; $wtzdata["Bogota, Lima, Quito, Rio Branco"] = "America/Bogota"; $wtzdata["Caracas"] = "America/Caracas"; $wtzdata["Santiago"] = "America/Santiago"; $wtzdata["La Paz"] = "America/La_Paz"; $wtzdata["Faukland Islands"] = "Atlantic/Stanley"; $wtzdata["Brazil"] = "America/Campo_Grande"; $wtzdata["Atlantic Time (Goose Bay)"] = "America/Goose_Bay"; $wtzdata["Atlantic Time (Canada)"] = "America/Glace_Bay"; $wtzdata["Newfoundland"] = "America/St_Johns"; $wtzdata["UTC-3"] = "America/Araguaina"; $wtzdata["Montevideo"] = "America/Montevideo"; $wtzdata["Miquelon, St. Pierre"] = "America/Miquelon"; $wtzdata["Greenland"] = "America/Godthab"; $wtzdata["Buenos Aires"] = "America/Argentina/Buenos_Aires"; $wtzdata["Brasilia"] = "America/Sao_Paulo"; $wtzdata["Mid-Atlantic"] = "America/Noronha"; $wtzdata["Cape Verde Is."] = "Atlantic/Cape_Verde"; $wtzdata["Azores"] = "Atlantic/Azores"; $wtzdata["Greenwich Mean Time : Belfast"] = "Europe/Belfast"; $wtzdata["Greenwich Mean Time : Dublin"] = "Europe/Dublin"; $wtzdata["Greenwich Mean Time : Lisbon"] = "Europe/Lisbon"; $wtzdata["Greenwich Mean Time : London"] = "Europe/London"; $wtzdata["Monrovia, Reykjavik"] = "Africa/Abidjan"; $wtzdata["Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"] = "Europe/Amsterdam"; $wtzdata["Belgrade, Bratislava, Budapest, Ljubljana, Prague"] = "Europe/Belgrade"; $wtzdata["Brussels, Copenhagen, Madrid, Paris"] = "Europe/Brussels"; $wtzdata["West Central Africa"] = "Africa/Algiers"; $wtzdata["Windhoek"] = "Africa/Windhoek"; $wtzdata["Beirut"] = "Asia/Beirut"; $wtzdata["Cairo"] = "Africa/Cairo"; $wtzdata["Gaza"] = "Asia/Gaza"; $wtzdata["Harare, Pretoria"] = "Africa/Blantyre"; $wtzdata["Jerusalem"] = "Asia/Jerusalem"; $wtzdata["Minsk"] = "Europe/Minsk"; $wtzdata["Syria"] = "Asia/Damascus"; $wtzdata["Moscow, St. Petersburg, Volgograd"] = "Europe/Moscow"; $wtzdata["Nairobi"] = "Africa/Addis_Ababa"; $wtzdata["Tehran"] = "Asia/Tehran"; $wtzdata["Abu Dhabi, Muscat"] = "Asia/Dubai"; $wtzdata["Yerevan"] = "Asia/Yerevan"; $wtzdata["Kabul"] = "Asia/Kabul"; $wtzdata["Ekaterinburg"] = "Asia/Yekaterinburg"; $wtzdata["Tashkent"] = "Asia/Tashkent"; $wtzdata["Chennai, Kolkata, Mumbai, New Delhi"] = "Asia/Kolkata"; $wtzdata["Kathmandu"] = "Asia/Katmandu"; $wtzdata["Astana, Dhaka"] = "Asia/Dhaka"; $wtzdata["Novosibirsk"] = "Asia/Novosibirsk"; $wtzdata["Yangon (Rangoon)"] = "Asia/Rangoon"; $wtzdata["Bangkok, Hanoi, Jakarta"] = "Asia/Bangkok"; $wtzdata["Krasnoyarsk"] = "Asia/Krasnoyarsk"; $wtzdata["Beijing, Chongqing, Hong Kong, Urumqi"] = "Asia/Hong_Kong"; $wtzdata["Irkutsk, Ulaan Bataar"] = "Asia/Irkutsk"; $wtzdata["Perth"] = "Australia/Perth"; $wtzdata["Eucla"] = "Australia/Eucla"; $wtzdata["Osaka, Sapporo, Tokyo"] = "Asia/Tokyo"; $wtzdata["Seoul"] = "Asia/Seoul"; $wtzdata["Yakutsk"] = "Asia/Yakutsk"; $wtzdata["Adelaide"] = "Australia/Adelaide"; $wtzdata["Darwin"] = "Australia/Darwin"; $wtzdata["Brisbane"] = "Australia/Brisbane"; $wtzdata["Hobart"] = "Australia/Hobart"; $wtzdata["Vladivostok"] = "Asia/Vladivostok"; $wtzdata["Lord Howe Island"] = "Australia/Lord_Howe"; $wtzdata["Solomon Is., New Caledonia"] = "Etc/GMT-11"; $wtzdata["Magadan"] = "Asia/Magadan"; $wtzdata["Norfolk Island"] = "Pacific/Norfolk"; $wtzdata["Anadyr, Kamchatka"] = "Asia/Anadyr"; $wtzdata["Auckland, Wellington"] = "Pacific/Auckland"; $wtzdata["Fiji, Kamchatka, Marshall Is."] = "Etc/GMT-12"; $wtzdata["Chatham Islands"] = "Pacific/Chatham"; $wtzdata["Nuku'alofa"] = "Pacific/Tongatapu"; $wtzdata["Kiritimati"] = "Pacific/Kiritimati"; $wtzdata["Central Standard Time"] = "America/Chicago"; // manual entries $wtzdata["GMT -0500 (Standard) / GMT -0400 (Daylight)"] = "America/New_York"; $wtzdata["Eastern Standard Time"] = "America/New_York"; $wtzdata["W. Europe Standard Time"] = "Europe/Paris"; $wtzdata["E. Europe Standard Time"] = "Europe/Helsinki"; $wtzdata["FLE Standard Time"] = "Europe/Helsinki"; $wtzdata["Mountain Standard Time"] = "America/Denver"; $wtzdata["Romance Standard Time"] = "Europe/Brussels"; $wtzdata["GMT Standard Time"] = "UTC"; $wtzdata["Tasmania Standard Time"] = "Australia/Hobart"; // Lets check if a file for custom timezones exists if (JFile::exists(JPATH_COMPONENT_SITE . '/libraries/ical_custom_timezones.php')) { //Load the custom file once include('ical_custom_timezones.php'); } $wtzid = str_replace('"','',$wtzid); return array_key_exists($wtzid,$wtzdata ) ? $wtzdata[$wtzid] : $wtzid; } function handleDate($key, $value) { $rawvalue = $value; // we have an array of exdates if (JString::strpos($key,"EXDATE")===0 && JString::strpos($value,",")>0){ $parts = explode(",",$value); $value = array(); foreach ($parts as $val){ $value[] = $this->unixTime($val); } } else { $tz = false; if (JString::strpos($key,"TZID=")>0){ $parts = explode(";",$key); if (count($parts)>=2 && JString::strpos($parts[1],"TZID=")!==false){ $tz = str_replace("TZID=", "",$parts[1]); $tz = iCalImport::convertWindowsTzid($tz); } } $value = $this->unixTime($value, $tz); } $parts = explode(";",$key); if (count($parts)<2 || JString::strlen($parts[1])==0) { $rawkey=$key."RAW"; return array($key,$value, $rawkey, $rawvalue); } $key = $parts[0]; $rawkey=$key."RAW"; return array($key,$value, $rawkey, $rawvalue); } function handleDuration($key,$value) { $rawvalue = $value; // strip "P" from the string $value = str_replace('P', '', $value); // split it out intyo W D H M S preg_match("/([0-9]*W)*([0-9]*D)*T?([0-9]*H)*([0-9]*M)*([0-9]*S)*/",$value,$details); @list($temp,$w,$d,$h,$min,$s)=$details; $duration = 0; $multiplier=1; $duration += intval(str_replace('S','',$s))*$multiplier; $multiplier=60; $duration += intval(str_replace('M','',$min))*$multiplier; $multiplier=3600; $duration += intval(str_replace('H','',$h))*$multiplier; $multiplier=86400; $duration += intval(str_replace('D','',$d))*$multiplier; $multiplier=604800; $duration += intval(str_replace('W','',$w))*$multiplier; $rawkey=$key."RAW"; return array($key, $duration, $rawkey, $rawvalue); } /** * Compare two unix timestamp * * @param array $a * @param array $b * @return integer */ function comparedates($a, $b) { if (!array_key_exists('DTSTART',$a) || !array_key_exists('DTSTART',$b) ){ echo "help<br/>"; } if ($a['DTSTART'] == $b['DTSTART']) return 0; return ($a['DTSTART'] > $b['DTSTART'])? +1 : -1; } // from http://fr3.php.net/manual/en/function.mb-detect-encoding.php#50087 function is_utf8($string) { // From http://w3.org/International/questions/qa-forms-utf-8.html $result = preg_match('%^(?: [\x09\x0A\x0D\x20-\x7E] # ASCII | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 )*$%xs', $string); return $result; } // function is_utf8 // from http://fr3.php.net/manual/en/function.mb-detect-encoding.php#68607 function detectUTF8($string) { return preg_match('%(?: [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte |\xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs |[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte |\xED[\x80-\x9F][\x80-\xBF] # excluding surrogates |\xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 |[\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 |\xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 )+%xs', $string); } }