403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/calendar/lib/ical/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/calendar/lib/ical/icsbuilder.php
<?php
namespace Bitrix\Calendar\ICal;

use Bitrix\Calendar\Core\Base\DateTimeZone;
use Bitrix\Calendar\Core\Event\Properties\ExcludedDatesCollection;
use Bitrix\Calendar\Core\Event\Properties\RecurringEventRules;

class IcsBuilder {
	//const DT_FORMAT = 'Ymd\THis\Z';
	const
		PRODID = '-//Bitrix//Bitrix Calendar//EN',
		DATE_FORMAT = 'Ymd',
		DATETIME_FORMAT = 'Ymd\THis',
		TIME_FORMAT = 'His',
		UTC_DATETIME_FORMAT = 'Ymd\\THis\\Z',
		DEFAULT_DATETIME_FORMAT = 'd.m.Y H:i:s'
	;

	protected const DAY_LENGTH = 86400;

	protected
		$fullDayMode = false,
		$organizer,
		$timezoneFrom,
		$timezoneTo,
		$attendees = [],
		$properties = [];

	protected ?RecurringEventRules $rrule = null;
	protected ?ExcludedDatesCollection $excludeDates = null;

	private
		$availableProperties = [
		'summary',
		'description',
		'dtstart',
		'dtend',
		'dtstamp',
		'location',
		'url',
		'alarm',
		'transp',
		'status',
		'uid',
		'attendee',
		'created',
		'last-modified',
		'sequence',
		'transp',
		'rrule',
		'priority',
	];
	private static
		$METHOD = 'REQUEST';


	/**
	 * Constructor.
	 *
	 * @param array $properties list of properties.
	 */
	public function __construct($properties = [], $config = [])
	{
		$this->setProperties($properties);
		$this->setConfig($config);
	}

	public function setProperties($properties)
	{
		if (is_array($properties))
		{
			foreach ($properties as $key => $value)
			{
				if (in_array($key, $this->availableProperties) && !empty($value))
				{
					$this->properties[$key] = $this->prepareValue($value, $key);
				}
			}
		}
	}

	public function setConfig($config)
	{
		if (is_array($config))
		{
			if (isset($config['timezoneFrom']))
			{
				$this->timezoneFrom = $config['timezoneFrom'];
			}
			if (isset($config['timezoneTo']))
			{
				$this->timezoneTo = $config['timezoneTo'];
			}
		}
	}

	public function setFullDayMode($value)
	{
		$this->fullDayMode = $value;
	}

	public function setOrganizer($name, $email, $phone)
	{
		$this->organizer = ['name' => $name, 'email' => $email, 'phone' => $phone];
	}

	public function setAttendees($attendeeDataList = [])
	{
		if (is_array($attendeeDataList))
		{
			foreach($attendeeDataList as $attendeeData)
			{
				$this->attendees[] = $attendeeData;
			}
		}
	}

	public function setRrule(RecurringEventRules $rrule): void
	{
		$this->rrule = $rrule;
	}

	public function setExclude(ExcludedDatesCollection $excludeDates): void
	{
		$this->excludeDates = $excludeDates;
	}

	public function render()
	{
		return implode("\r\n", $this->buildBody());
	}

	private function buildBody()
	{
		// Build ICS properties - add header
		$ics_props = [
			'BEGIN:VCALENDAR',
			'PRODID:'.self::PRODID,
			'VERSION:2.0',
			'CALSCALE:GREGORIAN',
			'METHOD:'.self::$METHOD,
			'BEGIN:VEVENT'
		];

		$props = [];

		// Add organizer field
		if (isset($this->organizer['email']))
		{
			$props[self::formatOrganizerKey($this->organizer)] = self::formatEmailValue($this->organizer['email']);
		}
		else if (isset($this->organizer['phone']))
		{
			$props[self::formatOrganizerKey($this->organizer)] = self::formatPhoneValue($this->organizer['phone']);
		}

		// Add attendees
		if (is_array($this->attendees))
		{
			foreach($this->attendees as $k => $attendee)
			{
				$props[self::formatAttendeeKey($attendee)] = self::formatEmailValue($attendee['email']);
			}
		}

		// Build ICS properties - add header
		foreach($this->properties as $k => $v)
		{
			switch ($k)
			{
				case 'dtstamp':
					$props['DTSTAMP'] = self::formatDateTimeValue($v);
					break;
				case 'url':
					$props['URL;VALUE=URI'] = $v;
					break;
				case 'dtstart':
				case 'dtend':
					if ($this->fullDayMode)
					{
						$props[mb_strtoupper($k).';VALUE=DATE'] = self::formatDateValue($v);
					}
					else
					{
						$tzid = ($k === 'dtstart') ? $this->timezoneFrom : $this->timezoneTo;
						$props[mb_strtoupper($k).';TZID='.$tzid] = self::formatDateTimeValue($v);
					}

					break;
				case 'last-modified':
					$props[mb_strtoupper($k)] = self::formatDateTimeValue($v);
					break;
				case 'priority':
					$priority = match ($v)
					{
						'low' => 9,
						'high' => 1,
						default => 5,
					};
					$props[mb_strtoupper($k)] = $priority;
					break;
				default:
					$props[mb_strtoupper($k)] = $v;
			}
		}

		if ($this->rrule !== null)
		{
			$props['RRULE'] = self::prepareRecurrenceRule($this->rrule, $this->timezoneTo);
		}

		if ($this->excludeDates && $this->rrule)
		{
			$props['EXDATE'] = $this->formatExcludedDates($this->prepareExcludedDates());
		}

		// Append properties
		foreach ($props as $k => $v)
		{
			switch ($k)
			{
				case 'ALARM':
					$ics_props[] = 'BEGIN:VALARM';
					$ics_props[] = 'TRIGGER:-PT' . $props['ALARM'];
					$ics_props[] = 'ACTION:DISPLAY';
					$ics_props[] = 'END:VALARM';
					break;
				case 'EXDATE':
					$ics_props[] = $k . $v;
					break;
				default:
					$ics_props[] = "$k:$v";
			}
		}

		// Build ICS properties - add footer
		$ics_props[] = 'END:VEVENT';
		$ics_props[] = 'END:VCALENDAR';

		return $ics_props;
	}

	private function prepareExcludedDates(): array
	{
		$result = [];
		$exDate = $this->excludeDates->getCollection();

		foreach ($exDate as $date)
		{
			$formattedDate = date('Ymd', MakeTimeStamp($date->getFields()['date']));
			if ($this->fullDayMode)
			{
				$result[] = [
					'VALUE' => $formattedDate,
					'PARAMETERS' => ['VALUE' => 'DATE'],
				];
			}
			else
			{
				$result[] = [
					'VALUE' => sprintf(
						'%sT%s',
						$formattedDate,
						$this->formatDateTimeValue($this->properties['dtstart'], self::TIME_FORMAT)
					),
					'PARAMETERS' => ['TZID' => $this->prepareTimeZone($this->timezoneFrom)],
				];
			}
		}

		return $result;
	}

	private function prepareTimeZone(?DateTimeZone $timeZone): string
	{
		if ($timeZone)
		{
			return $timeZone->getTimeZone()->getName();
		}

		return 'UTC';
	}

	private function formatExcludedDates(array $preparedExDate): string
	{
		$timezone = null;
		$dates = [];

		foreach ($preparedExDate as $date)
		{
			$timezone = $date['PARAMETERS']['TZID'] ?? null;
			$dates[] = $date['VALUE'];
		}

		$timezone = $timezone ? ';TZID=' . $timezone : ';VALUE=DATE';

		return $timezone . ':' . implode(',', $dates);
	}

	private function prepareValue($val, $key = false)
	{
		switch($key)
		{
//			case 'dtstamp':
//			case 'dtstart':
//			case 'dtend':
//				$val = $this->formatDateValue($val);
//				break;
			default:
				$val = $this->escapeString($val);
		}
		return $val;
	}

	private static function formatDateValue($timestamp)
	{
		$dt = new \DateTime();
		$dt->setTimestamp($timestamp);
		return $dt->format(self::DATE_FORMAT);
	}

	private static function formatDateTimeValue($timestamp, string $format = self::DATETIME_FORMAT)
	{
		$dt = new \DateTime();
		if ($timestamp)
		{
			$dt->setTimestamp($timestamp);
		}
		return $dt->format($format);
	}

	private static function formatEmailValue($email)
	{
		return 'mailto:'.$email;
	}

	private static function formatPhoneValue($phone): string
	{
		return 'tel:'.$phone;
	}


	private static function formatAttendeeKey($attendee)
	{
		$key = 'ATTENDEE';
		$key .= ';CUTYPE=INDIVIDUAL';
		//$key .= ';PARTSTAT=ACCEPTED'; // NEEDS-ACTION
		$key .= ';RSVP=TRUE';
		$key .= ';CN='.$attendee['email'];
		return $key;
	}

	private static function formatOrganizerKey($organizer)
	{
		$key = 'ORGANIZER';
		if ($organizer['name'])
		{
			$key .= ';CN='.$organizer['name'];
		}
		return $key;
	}

	public static function prepareRecurrenceRule(RecurringEventRules $rrule, ?DateTimeZone $timeZone): string
	{
		$result = 'FREQ=' . $rrule->getFrequency();
		if ($rrule->getInterval())
		{
			$result .= ';INTERVAL=' . $rrule->getInterval();
		}
		if ($rrule->getByday())
		{
			$result .= ';BYDAY=' . implode(',', $rrule->getByday());
		}
		if ($rrule->getCount())
		{
			$result .= ';COUNT=' . $rrule->getCount();
		}
		else if (
			$rrule->getUntil()
			&& $rrule->getUntil()->getDate()->getTimestamp()
			&& $rrule->getUntil()->getDate()->getTimestamp() < 2145830400
		)
		{
			$offset = 0;
			if ($timeZone)
			{
				$offset = $timeZone->getTimeZone()->getOffset(new \DateTime('now', $timeZone->getTimeZone()));
			}

			$untilTimestamp = $rrule->getUntil()->getDate()->getTimestamp() + (self::DAY_LENGTH - 1) - $offset;
			$result .= ';UNTIL=' . date('Ymd\\THis\\Z', $untilTimestamp);
		}

		return $result;
	}

	private static function escapeString($str)
	{
		return preg_replace('/([\,;])/','\\\$1', $str);
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit