<?php
/***********************************************
* File	  :   atmailcalendar.php
* Descr	 :   This backend is based on
*			   'BackendDiff' and implements a
*			   calendar interface
*
* Original by Zarafa Deutschland GmbH released under GPLv2.
* Modifications by Atmail published under GPLv2
* Consult LICENSE file for details
************************************************/

require_once( dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'bootloader.php');
//require_once( dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR. '..' . DIRECTORY_SEPARATOR . 'application' . DIRECTORY_SEPARATOR . 'models' . DIRECTORY_SEPARATOR . 'users.php');
require_once('diffbackend.php');
Zend_Registry::set('InDbAsArray', false); //true = Array, false = Serialized
Zend_Registry::set('totalCycleTime', 0);
Zend_Registry::set('totalCyclesNumber', 1);

// Alias /Microsoft-Server-ActiveSync /usr/local/atmail/webmail/push/index.php<?php


class BackendAtmailCalendar extends BackendDiff 
{

	var $_user;
	var $_devid;
	var $_protocolversion;
	var $_calnamesCache;
	
	public function Logon($user, $domain, $password)
	{

        //debugLog( __FILE__ . ' #' . __LINE__ . ': Logon(' . $user . ', ' . $domain . ')');
		
		//local user must exist in the db to have an calendar
		$authSuccess = users::auth( $user, $password );
		$this->_Password = $password;
		if( $authSuccess == true )
		{
			$this->_Account = $user;
			Zend_Registry::set('Account', $user);
			return true;
		}
		else
		{
			if( strpos($user, '@') === false )
			{
				$authSuccess = users::auth( $user.'@'.$domain, $password );
				if( $authSuccess )
				{
					$this->_Account = $user.'@'.$domain;
					Zend_Registry::set('Account', $this->_Account);
					return true;
				}
			}
			$this->_Password = '';
			return false;
		}
	}
	
	function Setup($user, $devid, $protocolversion)
	{
		$this->_user = $user;
		$this->_devid = $devid;
		$this->_protocolversion = $protocolversion;	
		$this->_userTZ = users::getAllUserData($this->_Account);
		$this->_userTZ = $this->_userTZ['UserSettings']['TimeZone'];
		$this->_calendar = new calendar( array('TimeZone' => $this->_userTZ, 'Account' => $this->_Account, 'Password' => $this->_Password, 'Calendar' => 'calendar') );
        //debugLog( __FILE__ . ' #' . __LINE__ . ': as ' . $user . ', ' . $devid . ', ' . $protocolversion);
		return true;
	}

	function GetFolderList() 
	{
        global $user;
		$this->_calnamesCache = $this->_calendar->getPushCalHref();

		//try find Personal, else only show first one.
		
		$foundPersonal = false;
		foreach($this->_calnamesCache as $folder)
		{
			
			if( $folder['displayname'] == 'Private' && $folder['calendar_owner'] == $user )
			{
				
				$foundPersonal = true;
				$this->_calnamesCache = array($folder);
				
			}
			
		}
		if( !$foundPersonal )
			$this->_calnamesCache = array($this->_calnamesCache[0]);
			
		$calendars = array();
		foreach($this->_calnamesCache as $folder)
		{
			$folder = $this->StatFolder($folder['relative_href']);
			$calendars[] = $folder;
        }
		return $calendars;

	}

	function StatFolder($id)
	{

        //debugLog( __FILE__ . ' #' . __LINE__ . ':StatFolder('.$id.')');
		$folder = $this->GetFolder($id);
		$stat = array();
		$stat["id"] = $id;
		$stat["parent"] = $folder->parentid;
		$stat["mod"] = $folder->displayname;
        return $stat;

	}

	function GetFolder($id)
	{
		
        //debugLog( __FILE__ . ' #' . __LINE__ . ':GetFolder('.$id.')');
		$this->_calnamesCache = $this->_calendar->getPushCalHref();
		$foundfolder = false;
		// try and find the id in the cache
		foreach($this->_calnamesCache as $folder)
		{
			if($folder['relative_href'] == $id)
			{
				$foundfolder = $folder;
			}
		}
		if(!$foundfolder)
		{
			// we didn't find the id, lets refresh the calname cache
			$this->_calnamesCache = $this->_calendar->getCalNames();

			// try and find the id in the cache again
			foreach($this->_calnamesCache as $folder)
			{
				if($folder['relative_href'] == $id)
				{
					$foundfolder = $folder;
				}
			}
		}
		
		if(!$foundfolder)
		{
			// we still failed!
			return false;
		}
		
		$folder = new SyncFolder();
		$folder->serverid = $foundfolder['relative_href'];
		$folder->parentid = "0";
		$folder->displayname = $foundfolder['displayname'];
		if($folder->displayname == 'calendar')
			$folder->displayname = 'Private';
		$folder->type = SYNC_FOLDER_TYPE_APPOINTMENT;

		return $folder;		
	}

	function GetMessageList($folderid, $cutoffdate) 
	{
		
        //debugLog( __FILE__ . ' #' . __LINE__ . ': $folderid = ' . $folderid . ', date(\'r\', ' . $cutoffdate . ') = ' . date('r', $cutoffdate) . " ################################################");
		//$now = new Date();
		//$nowUnixtimestamp = $now->getTime();
		$nowUnixtimestamp = strtotime("+2 weeks");
		//$nowUnixtimestamp = $now->format('%G-%m-%d %R');
		if( !is_int($cutoffdate) )
		{
			
			$cutoffUnixtimestamp = strtotime($cutoffdate);
			
		}	
		else if( $cutoffdate > 84200 )
		{		
			//$cutoff = new Date($cutoffdate);
			//$cutoffUnixtimestamp = $cutoff->getTime();
			//$cutoffUnixtimestamp = $cutoff->format('%G-%m-%d %R');
			$cutoffUnixtimestamp = $cutoffdate;
			
		}
		else
		{
			//if device is asking for all data cinse epoch then only send 1 weeks data.
			$cutoffUnixtimestamp = time() - (60 * 60 * 24 * 7); // one weeks data
			
		}

		$events = $this->_calendar->getPushRange($cutoffUnixtimestamp, $nowUnixtimestamp, null, $folderid, false);

		$messages = array();
		
		foreach ($events as $event)
		{
			$message = array();
			$message["id"] = $event['id'];
			if( empty($event['DateModified']) || !isset($event['DateModified']) || $event['DateModified'] == '' )
			{
				
				$event['DateModified'] = (int)(time()-60);
				
			}
			if(is_int($event['DateModified']))
			{
				$message["mod"] = $event['DateModified'];
			}
			else
			{	
				
				//DateModified appears to be in the Servers _userTZ locale and not the event TZ
				$oldtz = date_default_timezone_get();
				date_default_timezone_set("GMT");
				$message['mod'] = strtotime($event['DateModified']);
				date_default_timezone_set($oldtz);
		
			}
			$message["flags"] = 1;
			
			$messages[] = $message;  

		}
		return $messages;
		
	}

	function StatMessage($folderid, $id) 
	{


		// Optimize, we just want the date modified, nothing else
		$event = $this->_calendar->get_record_modified($id, $folderid);
        if($event === false)
        {
            return array();
        }

		$oldtz = date_default_timezone_get();
        date_default_timezone_set("GMT");

        //if no date modified, then push anyway as modified now
        if( empty($event['DateModified']) || $event['DateModified'] == '' )
        {

            $event['DateModified'] = (int)(time()-60);//modified 60 secs ago

        }

        $message = array();
        $message["id"] = $id;

        if(is_int($event['DateModified']))
        {

            $message["mod"] = $event['DateModified'];

        }
        else
        {

            $message['mod'] = strtotime($event['DateModified']);
        }

		$message["flags"] = 1;
		date_default_timezone_set($oldtz);

		return $message;
		
	}

	function GetMessage($folderid, $id, $truncsize, $mimesupport = 0) 
	{
        global $protocolversion;

		$event_in = $this->_calendar->get_record($id, $folderid);

		$event=new SyncAppointment();
		$event->uid = $event_in['id'];//hex2bin($event_in['id']);
		$event->dtstamp = time();
		
		//$event->timezone = '+0400';
		if( empty($event_in['timezone']) || !isset($event_in['timezone']) || $event_in['timezone'] == '' || $event_in['timezone'] == 'None' || $event_in['timezone'] == null )
			$event->timezone = $this->_userTZ;
		else
			$event->timezone = $event_in['timezone'];
		
		//Switch using local time to users set local time, else leave using servers local time (would normally be the same)
		$oldtz = @date_default_timezone_get();
        @date_default_timezone_set($event->timezone);

        $event->subject=$event_in['Title'];
		$event->starttime = strtotime($event_in['DateStartCal'] . ' ' . $event_in['DateStartTime']); // in users locale TZ
		$event->endtime = strtotime($event_in['DateEndCal'] . ' ' . $event_in['DateEndTime']); // in users locale TZ

		// set private
		$event->sensitivity = "2";
		
		#	$event->reminder=$event['alarm'];
		$event->reminder=NULL;
		$event->location=$event_in['Location'];
		$event->busystatus="2";
		//Availability
		// 2 = busy
		// 0 = free
		// 1 = tentative
		// 3 = outofoffice
		$event->busystatus="2";
        $body = $event_in['CalMessage'];
        if($protocolversion >= 12)
        {
            $event->body=$event_in['CalMessage'];

            $syncHtmlBody = new SyncHtmlBody();
            $syncHtmlBody->bodydata = $body;
            $syncHtmlBody->bodyestimateddatasize = strlen($body);
            $syncHtmlBody->bodytype = SYNC_AIRSYNCBASE_BODYPREFERENCE_TYPE_PLAIN;
            $syncHtmlBody->bodytruncated = 0;
            $event->body = $syncHtmlBody;
        }
        else
        {
    		$event->body=$body;
        }
		//sensitivity 
		$event->meetingstatus="0";
		$event->alldayevent="0";
		//timezone must be fixed //GMT
        if($protocolversion >= 12 && $event->timezone != '')
        {
            $vTimezone = calendar::getVTIMEZONE($event->timezone);
            if($vTimezone !== false)
            {
                $timezone = Sabre_VObject_Reader::read(calendar::getVTIMEZONE($event->timezone));
                if($timezone !== false)
                {
                    $bias = $timezone->{"STANDARD"}->{"TZOFFSETTO"}->value;
                    $bias = -1 * ($bias / 100) * 60 + $bias % 100;
                    $timezone = array('bias' => $bias,
                                'standardName' => '', //$timezone->{"TZID"}->value,
                                'standardYear' => 0,
                                'standardMonth' => 0,
                                'standardDayOfWeek' => 0,
                                'standardDay' => 0,
                                'standardHour' => 0,
                                'standardMinute' => 0,
                                'standardSecond' => 0,
                                'standardMilliseconds' => 0,
                                'standardBias' => 0,
                                'daylightName' => '',
                                'daylightYear' => 0,
                                'daylightMonth' => 0,
                                'daylightDayOfWeek' => 0,
                                'daylightDay' => 0,
                                'daylightHour' => 0,
                                'daylightMinute' => 0,
                                'daylightSecond' => 0,
                                'daylightMilliseconds' => 0,
                                'daylightBias' => -60
                                );
                    $event->timezone = $this->_packTimezoneInfo($timezone);
                }
            }
        }
        else
        {
    		$event->timezone = "xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==" ;
        }


		//$event->timezone="";
		$event->bodytruncated = 0;  
	
		$event->organizername='';
		$event->organizeremail=w2u($this->_Account);

		//reccurence process
		if (is_array($event_in['recurrenceArray']))
		{
			$event->recurrence = $this->_calendar->RecurrenceArray2PushArray($event_in);

		}
		@date_default_timezone_set($oldtz);
		return $event;
	}

	function ChangeMessage($folderid, $id, $event) 
	{
		
		//TZ assumed to always be GMT, dates are returned as GMT stamps anyway.
		//Switch using local time to users set local time, else leave using servers local time (would normally be the same)
        //debugLog( __FILE__ . ' #' . __LINE__ . ': event times were: ' . $event->subject . ' to start at ' . "\n" . date('r',$event->starttime) . ' and end at ' . date('r',$event->endtime));

/*      $event Object
	    [content] => 
	    [attributes] => 
	    [flags] => 
	    [timezone] => xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==
	    [alldayevent] => 0
	    [busystatus] => 2
	    [dtstamp] => 1281072605
	    [endtime] => 1281081600
	    [sensitivity] => 2
	    [subject] => another eventukhgfEjhgfwurbuaehbfjwhrbf
	    [starttime] => 1281070800
	    [uid] => AB07EE13-6BC3-792F-3147-06944CA5F5B4
	    [meetingstatus] => 0
*/
		//in order to honour timezone rules, if existing appointment does not have tz info then we convert to user local time and save without timezone
		//if origional appointment contains TZ then convert to this TZ and save
		if( isset($event->timezone) )
		{ 
			

			$unpackedTZInfo = $this->_unpackTimezoneInfo($event->timezone);
			if( $unpackedTZInfo['bias']%60 != 0 )
			{
				
				$this->_userTZ = "Etc/GMT";
				
			}
			else
			{
				
				$offset = round($unpackedTZInfo['bias']/60,0);
				$this->_userTZ = "Etc/GMT" . ($offset<0?'-':'+') . abs($offset);
			
			}
			//the packed timezone info also contains dst offsets so without the MAPI table it is harder to calculate, so just use GMT.
		}

        $oldtz = date_default_timezone_get();
        if( !empty($this->_userTZ) && $this->_userTZ !== "Null" && $this->_userTZ !== 'None')
        {

            date_default_timezone_set($this->_userTZ);

        }
		
		$event_in = array();
		if( !empty($event->uid) )
			$event_in['id'] = $event->uid;
		
		if( !empty($event->subject) )
			$event_in['Title'] = $event->subject;
			
		if( !empty($event->dtstamp) )
		{
			$event_in['DateModified'] = date('Y-m-d H:i:s',$event->dtstamp); //in $this->_userTZ locale
		}
		else
		{
			
			$event_in['DateModified'] = date('Y-m-d H:i:s'); //in $this->_userTZ locale
			
		}
		if( !empty($event->alldayevent) )
			$event_in['AllDayEvent'] = $event->alldayevent;
		else
			$event_in['AllDayEvent'] = 0;
			
		if( !empty($event->location) )
			$event_in['Location'] = $event->location;
		if( !empty($event->body) )
			$event_in['CalMessage'] = $event->body;
		
		$event_id = $event_in['id'];
		$Task = 0;
		$UserFrom = $UserTo = $this->_Account;
		$Title = $event_in['Title'];
		if( isset($event_in['CalMessage']))
			$CalMessage = $event_in['CalMessage'];
		else
			$CalMessage = '';
		if( isset($event_in['Location']))
			$Location = $event_in['Location'];
		else
			$Location = '';
		if( isset($event_in['AllDayEvent']))
			$AllDayEvent = $event_in['AllDayEvent'];
		else
			$AllDayEvent = '';
		if(isset($event->reminder))
		{
			if($event->reminder == 0)
			{
				$alertType = "Date";
				$alertPosition = "";
				$alertTrigger = $event->starttime;
			}
			else
			{
				$alertType = "Minutes";
				$alertPosition = "Before";
				$alertTrigger = $event->reminder;
			}
		}
		else
		{
			$alertType = '';
			$alertTrigger = '';
			$alertPosition = '';
		}

		$Importance = '1';
		$Type = '';
		$Alert = 0;
		if( !empty($event->starttime) )
		{
			$DateStartLocal = date('Y-m-d H:i:s',$event->starttime); // in users $this->_userTZ locale
		}
		if( !empty($event->endtime) )
		{
			$DateEndLocal = date('Y-m-d H:i:s',$event->endtime); // in users $this->_userTZ locale
		}
		
		$Parent = '';
		$ReadSelectedUsers = '';
		$WriteSelectedUsers = '';
		$WriteSelectedGroups = '';
		$ReadSelectedGroups = '';
		$Permission = "wr";
		$relative_href = urldecode($folderid);

        if(is_object($CalMessage) && get_class($CalMessage) == "SyncHtmlBody")
        {
            $CalMessage = $CalMessage->bodydata;
        }

		if( !$id )
		{
			
			$args = array(
				'task' => $Task,
				'title' => $Title,
				'description' => $CalMessage,
				'dateStart' => $DateStartLocal,
				'dateEnd' => $DateEndLocal,
				'location' => $Location,
				'allDayEvent' => $AllDayEvent,
				'calendarUrl' => $relative_href,
				'timezone' => $this->_userTZ
			);

			$result = $this->_calendar->add_record(	$args );
			$id = $result[0];
			if( 
				isset($event->recurrence) && gettype( $event->recurrence ) == "object" || 
				isset($event->reminder)
			)
			{
				$recurrenceRules = $this->_calendar->PushArray2RecurrenceArray($event->recurrence);
				$args = array(
					'title' =>$Title, 
					'datestart' => $DateStartLocal, 
					'dateend' => $DateEndLocal, 
					'uid' => $id, 
					'description' => $CalMessage, 
					'location' => $Location, 
					'recurrencetype' => $recurrenceRules['RecurrenceType'], 
					'recurrenceendtype' => $recurrenceRules['recurrenceEndType'], 
					'recurrenceEndByDate' => $recurrenceRules['recurrenceEndByDate'], 
					'recurrenceEndAfterX' => $recurrenceRules['recurrenceEndAfterX'],
					'calendarUrl' => $relative_href,
					'alertType' => $alertType, 
					'alertTrigger' => $alertTrigger,
					'alertPosition' => $alertPosition,
					'recurrenceinterval' => $recurrenceRules['skipInterval'], 
					'timezone' => $this->_userTZ, 
					'preserveoriginaltz' => false
				);

				$this->_calendar->update_record($args);
			}
		}
		else
		{

            //debugLog( __FILE__ . ' #' . __LINE__ . ': Updating event');
			if( isset($event->recurrence) && gettype( $event->recurrence ) == "object" )
				$recurrenceRules = $this->_calendar->PushArray2RecurrenceArray($event->recurrence);
			else
			{
				$recurrenceRules = array();
				$recurrenceRules['RecurrenceType'] = 0;
				$recurrenceRules['recurrenceEndType'] = 0;
				$recurrenceRules['recurrenceEndByDate'] = 0;
				$recurrenceRules['recurrenceEndAfterX'] = 0;
				$recurrenceRules['skipInterval'] = 0;
			}

			$args = array(
				'title' =>$Title, 
				'datestart' => $DateStartLocal, 
				'dateend' => $DateEndLocal, 
				'uid' => $id, 
				'description' => $CalMessage, 
				'location' => $Location, 
				'recurrencetype' => $recurrenceRules['RecurrenceType'], 
				'recurrenceendtype' => $recurrenceRules['recurrenceEndType'], 
				'recurrenceEndByDate' => $recurrenceRules['recurrenceEndByDate'], 
				'recurrenceEndAfterX' => $recurrenceRules['recurrenceEndAfterX'],
				'calendarUrl' => $relative_href,
				'alertType' => $alertType, 
				'alertTrigger' => $alertTrigger,
				'alertPosition' => $alertPosition,
				'recurrenceinterval' => $recurrenceRules['skipInterval'], 
				'timezone' => $this->_userTZ, 
				'preserveoriginaltz' => false
			);
			$this->_calendar->update_record( $args );
		}
		date_default_timezone_set($oldtz);
		return $this->StatMessage($folderid, $id);
		
	}

	function DeleteMessage($folderid, $id) 
	{
		
        //debugLog( __FILE__ . ' #' . __LINE__ . ': ' . $folderid . " " .$id );
        try
		{
			$this->_calendar->delete_record($id, '', $folderid);		
		}
		catch( Exception $e )
		{
			
			//calendar event may not exist on server any more so ignore delete failure
			
		}
		return true;
	}

	function SendMail($rfc822, $forward = false, $reply = false, $parent = false)
	{
		return false;
	}

	function GetWasteBasket()
	{
		return false;
	}

	function GetAttachmentData($attname)
	{	
		return false;
	}

	function SetReadFlag($folderid, $id, $flags)
	{
		return false;
	}

	function MoveMessage($folderid, $id, $newfolderid)
	{
		return false;
	}

	// -----------------------------------

	function getPath()
	{	
		return str_replace('%u', $this->_user, VCARDDIR_DIR);
	}

	function escape($data)
	{
	
		if (is_array($data))
		{
		
			foreach ($data as $key => $val)
				$data[$key] = $this->escape($val);
			return $data;
			
		}
		$data = str_replace("\r\n", "\n", $data);
		$data = str_replace("\r", "\n", $data);
		$data = str_replace(array('\\', ';', ',', "\n"), array('\\\\', '\\;', '\\,', '\\n'), $data);
		return u2wi($data);
		
	}

	function unescape($data)
	{
	
		return str_replace(array('\\\\', '\\;', '\\,', '\\n','\\N'),array('\\', ';', ',', "\n", "\n"),$data);
	
	}
	
	private function convert_from_outlook_date($date)
	{

		$seconds = time(); // Current time in seconds

		$datecalc = $date; // This has the date
		$seconds = '';
		if (preg_match('/\.(.*)/', $date, $match))
			$seconds = $match[1];

		$datecalc = preg_replace('/\.(.*)/', '', $datecalc);

		// Number of days
		$datecalc = $datecalc - "25569";

		// Convert to seconds
		$datecalc = round($datecalc * 60 * 60 * 24);

		// Int rounds it up - 86400 seconds in 1 day 0.[secsyougiveme]
		$newsecs = round("0.$seconds"  * 86400);

		$datecalc = $datecalc + $newsecs;

        //debugLog("Date function, orig = $date , EPOC = $datecalc");
		return $datecalc;

	}

	/**
	     * decode timezone info from activesync
	     * 
	     * @param string $_packedTimezoneInfo the packed timezone info
	     * @return array
	     */
	    protected function _unpackTimezoneInfo($_packedTimezoneInfo)
	    {
	        $timezoneUnpackString = 'lbias/a64standardName/vstandardYear/vstandardMonth/vstandardDayOfWeek/vstandardDay/vstandardHour/vstandardMinute/vstandardSecond/vstandardMilliseconds/lstandardBias/a64daylightName/vdaylightYear/vdaylightMonth/vdaylightDayOfWeek/vdaylightDay/vdaylightHour/vdaylightMinute/vdaylightSecond/vdaylightMilliseconds/ldaylightBias';

	        $timezoneInfo = unpack($timezoneUnpackString, base64_decode($_packedTimezoneInfo));

	        return $timezoneInfo;
	    }

	    /**
	     * encode timezone info to activesync
	     * 
	     * @param array $_timezoneInfo
	     * @return string
	     */
	    protected function _packTimezoneInfo($_timezoneInfo) 
	    {
	        if (!is_array($_timezoneInfo)) {
	        	return null;
	        }

	        $packed = pack(
	            "la64vvvvvvvvla64vvvvvvvvl",
	            $_timezoneInfo["bias"], 
	            $_timezoneInfo["standardName"], 
	            $_timezoneInfo['standardYear'],
	            $_timezoneInfo["standardMonth"], 
	            $_timezoneInfo['standardDayOfWeek'],
	            $_timezoneInfo["standardDay"], 
	            $_timezoneInfo["standardHour"], 
	            $_timezoneInfo["standardMinute"], 
	            $_timezoneInfo['standardSecond'],
	            $_timezoneInfo['standardMilliseconds'],
	            $_timezoneInfo["standardBias"], 
	            $_timezoneInfo["daylightName"], 
	            $_timezoneInfo['daylightYear'],
	            $_timezoneInfo["daylightMonth"], 
	            $_timezoneInfo['daylightDayOfWeek'],
	            $_timezoneInfo["daylightDay"], 
	            $_timezoneInfo["daylightHour"], 
	            $_timezoneInfo["daylightMinute"], 
	            $_timezoneInfo['daylightSecond'],
	            $_timezoneInfo['daylightMilliseconds'],
	            $_timezoneInfo["daylightBias"] 
	        );

	        return base64_encode($packed);
	    }
	
}
