%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /proc/self/root/home/bitrix/www/bitrix/modules/bizproc/classes/general/
Upload File :
Create Path :
Current File : //proc/self/root/home/bitrix/www/bitrix/modules/bizproc/classes/general/calc.php

<?
class CBPCalc
{
	private $activity;
	private $arErrorsList = array();

	private static $weekHolidays;
	private static $yearHolidays;
	private static $startWorkDay;
	private static $endWorkDay;

	public function __construct($activity)
	{
		/** @var CBPActivity activity */
		$this->activity = $activity;
	}

	private function GetVariableValue($variable)
	{
		$variable = trim($variable);
		if (!preg_match(CBPActivity::ValuePattern, $variable))
			return null;

		return $this->activity->ParseValue($variable);
	}

	private function SetError($errnum, $errstr = '')
	{
		$this->arErrorsList[] = array($errnum, str_replace('#STR#', $errstr, $this->arAvailableErrors[$errnum]));
	}

	public function GetErrors()
	{
		return $this->arErrorsList;
	}

	/*
	Return array of polish notation
	array(
		key => array(value, self::Operation | self::Variable | self::Constant)
	)
	*/
	private function GetPolishNotation($text)
	{
		$text = trim($text);
		if (substr($text, 0, 1) === '=')
			$text = substr($text, 1);
		if (strpos($text, '{{=') === 0 && substr($text, -2) == '}}')
		{
			$text = substr($text, 3);
			$text = substr($text, 0, -2);
		}

		if (strlen($text) <= 0)
		{
			$this->SetError(1);
			return false;
		}

		$arPolishNotation = array();

		$arStack = array();
		$prev = '';
		$preg = '/
			\s*\(\s*                          |
			\s*\)\s*                          |
			\s*,\s*                           | # Combine ranges of variables
			\s*;\s*                           | # Combine ranges of variables
			\s*=\s*                           |
			\s*<=\s*                          |
			\s*>=\s*                          |
			\s*<>\s*                          |
			\s*<\s*                           |
			\s*>\s*                           |
			\s*&\s*                           | # String concatenation
			\s*\+\s*                          | # Addition or unary plus
			\s*-\s*                           |
			\s*\*\s*                          |
			\s*\/\s*                          |
			\s*\^\s*                          | # Exponentiation
			\s*%\s*                           | # Percent
			\s*[\d\.]+\s*                     | # Numbers
			\s*\'[^\']*\'\s*                  | # String constants in apostrophes
			\s*"[^"]*"\s*                     | # String constants in quotes
			(\s*\w+\s*\(\s*)                  | # Function names
			\s*'.CBPActivity::ValueInternalPattern.'\s*  | # Variables
			(?<error>.+)                                # Any erroneous substring
			/xi';
		while (preg_match($preg, $text, $match))
		{
			if (isset($match['error']))
			{
				$this->SetError(2, $match['error']);
				return false;
			}

			$str = trim($match[0]);
			if ($str === ",")
				$str = ";";

			if (isset($match[1]) && $match[1])
			{
				$str = strtolower($str);
				list($name, $left) = explode('(', $str);
				$name = trim($name);
				if (isset($this->arAvailableFunctions[$name]))
				{
					if (!$arStack)
					{
						array_unshift($arStack, array($name, $this->arPriority['f']));
					}
					else
					{
						while ($this->arPriority['f'] <= $arStack[0][1])
						{
							$op = array_shift($arStack);
							$arPolishNotation[] = array($op[0], self::Operation);
							if (!$arStack)
								break;
						}
						array_unshift($arStack, array($name, $this->arPriority['f']));
					}
				}
				else
				{
					$this->SetError(3, $name);
					return false;
				}
				$str = '(';
			}

			if ($str == '-' || $str == '+')
			{
				if ($prev == '' || in_array($prev, array('(', ';', '=', '<=', '>=', '<>', '<', '>', '&', '+', '-', '*', '/', '^')))
					$str .= 'm';
			}
			$prev = $str;

			switch ($str)
			{
				case '(':
					array_unshift($arStack, array('(', $this->arPriority['(']));
					break;
				case ')':
					while ($op = array_shift($arStack))
					{
						if ($op[0] == '(')
							break;
						$arPolishNotation[] = array($op[0], self::Operation);
					}
					if ($op == null)
					{
						$this->SetError(4);
						return false;
					}
					break;
				case ';' :      case '=' :      case '<=':      case '>=':
				case '<>':      case '<' :      case '>' :      case '&' :
				case '+' :      case '-' :      case '+m':      case '-m':
				case '*' :      case '/' :      case '^' :      case '%' :
					if (!$arStack)
					{
						array_unshift($arStack, array($str, $this->arPriority[$str]));
						break;
					}
					while ($this->arPriority[$str] <= $arStack[0][1])
					{
						$op = array_shift($arStack);
						$arPolishNotation[] = array($op[0], self::Operation);
						if (!$arStack)
							break;
					}
					array_unshift($arStack, array($str, $this->arPriority[$str]));
					break;
				default:
					if (substr($str, 0, 1) == '0' || (int) $str)
					{
						$arPolishNotation[] = array((float)$str, self::Constant);
						break;
					}
					if (substr($str, 0, 1) == '"' || substr($str, 0, 1) == "'")
					{
						$arPolishNotation[] = array(substr($str, 1, -1), self::Constant);
						break;
					}
					$arPolishNotation[] = array($str, self::Variable);
			}
			$text = substr($text, strlen($match[0]));
		}
		while ($op = array_shift($arStack))
		{
			if ($op[0] == '(')
			{
				$this->SetError(5);
				return false;
			}
			$arPolishNotation[] = array($op[0], self::Operation);
		}
		return $arPolishNotation;
	}

	public function Calculate($text)
	{
		if (!$arPolishNotation = $this->GetPolishNotation($text))
			return null;

		$stack = array();
		foreach ($arPolishNotation as $item)
		{
			switch ($item[1])
			{
				case self::Constant:
					array_unshift($stack, $item[0]);
					break;
				case self::Variable:
					array_unshift($stack, $this->GetVariableValue($item[0]));
					break;
				case self::Operation:
					switch ($item[0])
					{
						case ';':
							$arg2 = array_shift($stack);
							$arg1 = array_shift($stack);
							if (!is_array($arg1) || !isset($arg1[0]))
								$arg1 = array($arg1);
							$arg1[] = $arg2;
							array_unshift($stack, $arg1);
							break;
						case '=':
							$arg2 = array_shift($stack);
							$arg1 = array_shift($stack);
							array_unshift($stack, $arg1 == $arg2);
							break;
						case '<=':
							$arg2 = array_shift($stack);
							$arg1 = array_shift($stack);
							array_unshift($stack, $arg1 <= $arg2);
							break;
						case '>=':
							$arg2 = array_shift($stack);
							$arg1 = array_shift($stack);
							array_unshift($stack, $arg1 >= $arg2);
							break;
						case '<>':
							$arg2 = array_shift($stack);
							$arg1 = array_shift($stack);
							array_unshift($stack, $arg1 != $arg2);
							break;
						case '<':
							$arg2 = array_shift($stack);
							$arg1 = array_shift($stack);
							array_unshift($stack, $arg1 < $arg2);
							break;
						case '>':
							$arg2 = array_shift($stack);
							$arg1 = array_shift($stack);
							array_unshift($stack, $arg1 > $arg2);
							break;
						case '&':
							$arg2 = (string) array_shift($stack);
							$arg1 = (string) array_shift($stack);
							array_unshift($stack, $arg1 . $arg2);
							break;
						case '+':
							$arg2 = (float) array_shift($stack);
							$arg1 = (float) array_shift($stack);
							array_unshift($stack, $arg1 + $arg2);
							break;
						case '-':
							$arg2 = (float) array_shift($stack);
							$arg1 = (float) array_shift($stack);
							array_unshift($stack, $arg1 - $arg2);
							break;
						case '+m':
							$arg = (float) array_shift($stack);
							array_unshift($stack, $arg);
							break;
						case '-m':
							$arg = (float) array_shift($stack);
							array_unshift($stack, (-$arg));
							break;
						case '*':
							$arg2 = (float) array_shift($stack);
							$arg1 = (float) array_shift($stack);
							array_unshift($stack, $arg1 * $arg2);
							break;
						case '/':
							$arg2 = (float) array_shift($stack);
							$arg1 = (float) array_shift($stack);
							if (0 == $arg2)
							{
								$this->SetError(6);
								return null;
							}
							array_unshift($stack, $arg1 / $arg2);
							break;
						case '^':
							$arg2 = (float) array_shift($stack);
							$arg1 = (float) array_shift($stack);
							array_unshift($stack, pow($arg1, $arg2));
							break;
						case '%':
							$arg = (float) array_shift($stack);
							array_unshift($stack, $arg / 100);
							break;
						default:
							$func = $this->arAvailableFunctions[$item[0]]['func'];
							if ($this->arAvailableFunctions[$item[0]]['args'])
							{
								$arg = array_shift($stack);
								$val = $this->$func($arg);
							}
							else
							{
								$val = $this->$func();
							}
							$error = is_float($val) && (is_nan($val) || is_infinite($val));
							if ($error)
							{
								$this->SetError(8, $item[0]);
								return null;
							}
							array_unshift($stack, $val);
					}
			}
		}
		if (count($stack) > 1)
		{
			$this->SetError(7);
			return null;
		}
		return array_shift($stack);
	}

	private function ArrgsToArray($args)
	{
		if (!is_array($args))
			return array($args);

		$result = array();
		foreach ($args as $arg)
		{
			if (!is_array($arg))
			{
				$result[] = $arg;
			}
			else
			{
				foreach ($this->ArrgsToArray($arg) as $val)
					$result[] = $val;
			}
		}

		return $result;
	}

	private function FunctionAbs($num)
	{
		return abs((float) $num);
	}

	private function FunctionAnd($args)
	{
		if (!is_array($args))
			return (boolean) $args;

		$args = $this->ArrgsToArray($args);

		foreach ($args as $arg)
		{
			if (!$arg)
				return false;
		}
		return true;
	}

	private function FunctionDateAdd($args)
	{
		if (!is_array($args))
			$args = array($args);

		$ar = $this->ArrgsToArray($args);
		$date = array_shift($ar);
		$interval = array_shift($ar);

		if (($date = $this->makeTimestamp($date)) === false)
			return null;

		if (($interval == null) || (strlen($interval) <= 0))
			return $date;

		// 1Y2M3D4H5I6S, -4 days 5 hours, 1month, 5h

		$interval = trim($interval);
		$bMinus = false;
		if (substr($interval, 0, 1) === "-")
		{
			$interval = substr($interval, 1);
			$bMinus = true;
		}

		static $arMap = array("y" => "YYYY", "year" => "YYYY", "years" => "YYYY",
							"m" => "MM", "month" => "MM", "months" => "MM",
							"d" => "DD", "day" => "DD", "days" => "DD",
							"h" => "HH", "hour" => "HH", "hours" => "HH",
							"i" => "MI", "min" => "MI", "minute" => "MI", "minutes" => "MI",
							"s" => "SS", "sec" => "SS", "second" => "SS", "seconds" => "SS",
		);

		$arInterval = array();
		while (preg_match('/\s*([\d]+)\s*([a-z]+)\s*/i', $interval, $match))
		{
			$match2 = strtolower($match[2]);
			if (array_key_exists($match2, $arMap))
				$arInterval[$arMap[$match2]] = ($bMinus ? -intval($match[1]) : intval($match[1]));

			$p = strpos($interval, $match[0]);
			$interval = substr($interval, $p + strlen($match[0]));
		}

		$newDate = AddToTimeStamp($arInterval, $date);

		return ConvertTimeStamp($newDate, "FULL");
	}

	private function FunctionWorkDateAdd($args)
	{
		if (!is_array($args))
			$args = array($args);

		$ar = $this->ArrgsToArray($args);
		$date = array_shift($ar);
		$paramInterval = array_shift($ar);

		if (($date = $this->makeTimestamp($date)) === false)
			return null;

		if (($paramInterval == null) || (strlen($paramInterval) <= 0) || !CModule::IncludeModule('calendar'))
			return $date;

		$paramInterval = trim($paramInterval);
		$multiplier = 1;
		if (substr($paramInterval, 0, 1) === "-")
		{
			$paramInterval = substr($paramInterval, 1);
			$multiplier = -1;
		}

		$workDayInterval = $this->getWorkDayInterval();
		$intervalMap = array("d" => $workDayInterval, "day" => $workDayInterval, "days" => $workDayInterval,
							"h" => 3600, "hour" => 3600, "hours" => 3600,
							"i" => 60, "min" => 60, "minute" => 60, "minutes" => 60,
		);

		$interval = 0;
		while (preg_match('/\s*([\d]+)\s*([a-z]+)\s*/i', $paramInterval, $match))
		{
			$match2 = strtolower($match[2]);
			if (array_key_exists($match2, $intervalMap))
				$interval += intval($match[1]) * $intervalMap[$match2];

			$p = strpos($paramInterval, $match[0]);
			$paramInterval = substr($paramInterval, $p + strlen($match[0]));
		}

		$date = $this->getNearestWorkTime($date, $multiplier);
		if ($interval)
		{
			$days = (int) floor($interval / $workDayInterval);
			$hours = $interval % $workDayInterval;

			$remainTimestamp = $this->getWorkDayRemainTimestamp($date, $multiplier);

			if ($days)
				$date = $this->addWorkDay($date, $days * $multiplier);

			if ($hours > $remainTimestamp)
			{
				$date += $multiplier < 0 ? -$remainTimestamp -60 : $remainTimestamp + 60;
				$date = $this->getNearestWorkTime($date, $multiplier) + (($hours - $remainTimestamp) * $multiplier);
			}
			else
				$date += $multiplier * $hours;
		}

		return ConvertTimeStamp($date, "FULL");
	}

	private function makeTimestamp($date)
	{
		if (!$date)
			return false;
		if (intval($date)."!" === $date."!")
			return $date;

		if (($result = MakeTimeStamp($date, FORMAT_DATETIME)) === false)
		{
			if (($result = MakeTimeStamp($date, FORMAT_DATE)) === false)
			{
				if (($result = MakeTimeStamp($date, "YYYY-MM-DD HH:MI:SS")) === false)
				{
					$result = MakeTimeStamp($date, "YYYY-MM-DD");
				}
			}
		}
		return $result;
	}

	private function getWorkDayTimestamp($date)
	{
		return date('H', $date) * 3600 + date('i', $date) * 60;
	}

	private function getWorkDayRemainTimestamp($date, $multiplier = 1)
	{
		$dayTs = $this->getWorkDayTimestamp($date);
		list ($startSeconds, $endSeconds) = $this->getCalendarWorkTime();
		return $multiplier < 0 ? $dayTs - $startSeconds :$endSeconds - $dayTs;
	}

	private function getWorkDayInterval()
	{
		list ($startSeconds, $endSeconds) = $this->getCalendarWorkTime();
		return $endSeconds - $startSeconds;
	}

	private function isHoliday($date)
	{
		list($weekHolidays, $yearHolidays) = $this->getCalendarHolidays();

		$dayOfWeek = date('w', $date);
		if (in_array($dayOfWeek, $weekHolidays))
				return true;
		$dayOfYear = date('j.n', $date);
		if (in_array($dayOfYear, $yearHolidays, true))
			return true;

		return false;
	}

	private function isWorkTime($date)
	{
		$dayTs = $this->getWorkDayTimestamp($date);
		list ($startSeconds, $endSeconds) = $this->getCalendarWorkTime();
		return ($dayTs >= $startSeconds && $dayTs <= $endSeconds);
	}

	private function getNearestWorkTime($date, $multiplier = 1)
	{
		$reverse = $multiplier < 0;
		list ($startSeconds, $endSeconds) = $this->getCalendarWorkTime();
		$dayTimeStamp = $this->getWorkDayTimestamp($date);

		if ($this->isHoliday($date))
		{
			$date -= $dayTimeStamp;
			$date += $reverse? -86400 + $endSeconds : $startSeconds;
			$dayTimeStamp = $reverse? $endSeconds : $startSeconds;
		}

		if (!$this->isWorkTime($date))
		{
			$date -= $dayTimeStamp;

			if ($dayTimeStamp < $startSeconds)
			{
				$date += $reverse? -86400 + $endSeconds : $startSeconds;
			}
			else
			{
				$date += $reverse? $endSeconds : 86400 + $startSeconds;
			}
		}

		if ($this->isHoliday($date))
			$date = $this->addWorkDay($date, $reverse? -1 : 1);

		return $date;
	}

	private function addWorkDay($date, $days)
	{
		$delta = 86400;
		if ($days < 0)
			$delta *= -1;

		$days = abs($days);
		$iterations = 0;

		while ($days > 0 && $iterations < 1000)
		{
			++$iterations;
			$date += $delta;

			if ($this->isHoliday($date))
				continue;
			--$days;
		}

		return $date;
	}

	private function getCalendarHolidays()
	{
		if (static::$yearHolidays === null)
		{
			$calendarSettings = CCalendar::GetSettings();
			$weekHolidays = array(0, 6);
			$yearHolidays = array();

			if (isset($calendarSettings['week_holidays']))
			{
				$weekDays = array('SU' => 0, 'MO' => 1, 'TU' => 2, 'WE' => 3, 'TH' => 4, 'FR' => 5, 'SA' => 6);
				$weekHolidays = array();
				foreach ($calendarSettings['week_holidays'] as $day)
					$weekHolidays[] = $weekDays[$day];
			}

			if (isset($calendarSettings['year_holidays']))
			{
				foreach (explode(',', $calendarSettings['year_holidays']) as $yearHoliday)
				{
					$ardate = explode('.', trim($yearHoliday));
					if (count($ardate) == 2 && $ardate[0] && $ardate[1])
						$yearHolidays[] = (int)$ardate[0].'.'.(int)$ardate[1];
				}
			}
			static::$weekHolidays = $weekHolidays;
			static::$yearHolidays = $yearHolidays;
		}

		return array(static::$weekHolidays, static::$yearHolidays);
	}

	private function getCalendarWorkTime()
	{
		if (static::$startWorkDay === null)
		{
			$startSeconds = 0;
			$endSeconds = 24 * 3600 - 1;

			$calendarSettings = CCalendar::GetSettings();
			if (!empty($calendarSettings['work_time_start']))
			{
				$time = explode('.', $calendarSettings['work_time_start']);
				$startSeconds = $time[0] * 3600;
				if (!empty($time[1]))
					$startSeconds += $time[1] * 60;
			}

			if (!empty($calendarSettings['work_time_end']))
			{
				$time = explode('.', $calendarSettings['work_time_end']);
				$endSeconds = $time[0] * 3600;
				if (!empty($time[1]))
					$endSeconds += $time[1] * 60;
			}
			static::$startWorkDay = $startSeconds;
			static::$endWorkDay = $endSeconds;
		}
		return array(static::$startWorkDay, static::$endWorkDay);
	}

	private function FunctionAddWorkDays($args)
	{
		if (!is_array($args))
			$args = array($args);

		$ar = $this->ArrgsToArray($args);
		$date = array_shift($ar);
		$days = (int) array_shift($ar);

		if (($date = $this->makeTimestamp($date)) === false)
			return null;

		if ($days === 0 || !CModule::IncludeModule('calendar'))
			return $date;

		$date = $this->addWorkDay($date, $days);

		return ConvertTimeStamp($date, "FULL");
	}

	private function FunctionIsWorkDay($args)
	{
		if (!CModule::IncludeModule('calendar'))
			return null;

		if (!is_array($args))
			$args = array($args);

		$ar = $this->ArrgsToArray($args);
		$date = array_shift($ar);

		if (($date = $this->makeTimestamp($date)) === false)
			return null;

		return !$this->isHoliday($date);
	}

	private function FunctionIsWorkTime($args)
	{
		if (!CModule::IncludeModule('calendar'))
			return null;

		if (!is_array($args))
			$args = array($args);

		$ar = $this->ArrgsToArray($args);
		$date = array_shift($ar);

		if (($date = $this->makeTimestamp($date)) === false)
			return null;

		return !$this->isHoliday($date) && $this->isWorkTime($date);
	}

	private function FunctionDateDiff($args)
	{
		if (!is_array($args))
			$args = array($args);

		$ar = $this->ArrgsToArray($args);
		$date1 = array_shift($ar);
		$date2 = array_shift($ar);
		$format = array_shift($ar);

		if ($date1 == null || $date2 == null)
			return null;

		$df = $GLOBALS["DB"]->DateFormatToPHP(FORMAT_DATETIME);
		$df2 = $GLOBALS["DB"]->DateFormatToPHP(FORMAT_DATE);
		$date1Formatted = \DateTime::createFromFormat($df, $date1);
		if ($date1Formatted === false)
		{
			$date1Formatted = \DateTime::createFromFormat($df2, $date1);
			if ($date1Formatted)
			{
				$date1Formatted->setTime(0, 0);
			}
		}
		$date2Formatted = \DateTime::createFromFormat($df, $date2);
		if ($date2Formatted === false)
		{
			$date2Formatted = \DateTime::createFromFormat($df2, $date2);
			if ($date2Formatted)
			{
				$date2Formatted->setTime(0, 0);
			}
		}
		if ($date1Formatted === false || $date2Formatted === false)
		{
			return null;
		}

		$interval = $date1Formatted->diff($date2Formatted);

		return $interval === false? null : $interval->format($format);
	}

	private function FunctionDate($args)
	{
		$ar = $this->ArrgsToArray($args);
		$format = array_shift($ar);
		$date = array_shift($ar);

		if (!$format || !is_string($format))
		{
			return null;
		}

		$ts = $date ? $this->makeTimestamp($date) : time();

		if (!$ts)
		{
			return null;
		}

		return date($format, $ts);
	}

	private function FunctionFalse()
	{
		return false;
	}

	private function FunctionIf($args)
	{
		if (!is_array($args))
			return null;

		$expression = (boolean) array_shift($args);
		$ifTrue = array_shift($args);
		$ifFalse = array_shift($args);
		return $expression ? $ifTrue : $ifFalse;
	}

	private function FunctionIntval($num)
	{
		return intval($num);
	}

	private function FunctionFloatval($num)
	{
		return floatval($num);
	}

	private function FunctionNumberFormat($args)
	{
		$ar = $this->ArrgsToArray($args);
		$number = (float) array_shift($ar);
		$decimals = (int) (array_shift($ar) ?: 0);
		$decPoint = array_shift($ar);
		if ($decPoint === null)
		{
			$decPoint = '.';
		}
		$decPoint = (string) $decPoint;

		$thousandsSeparator = array_shift($ar);
		if ($thousandsSeparator === null)
		{
			$thousandsSeparator = ',';
		}
		$thousandsSeparator = (string) $thousandsSeparator;

		return number_format($number, $decimals, $decPoint, $thousandsSeparator);
	}

	private function FunctionMin($args)
	{
		if (!is_array($args))
			return (float) $args;

		foreach ($args as &$arg)
			$arg = (float) $arg;

		$args = $this->ArrgsToArray($args);
		return min($args);
	}

	private function FunctionMax($args)
	{
		if (!is_array($args))
			return (float) $args;

		foreach ($args as &$arg)
			$arg = (float) $arg;

		$args = $this->ArrgsToArray($args);
		return max($args);
	}

	private function FunctionRand($args)
	{
		$ar = $this->ArrgsToArray($args);
		$min = (int)array_shift($ar);
		$max = (int)array_shift($ar);
		if (!$max)
		{
			$max = mt_getrandmax();
		}

		return mt_rand($min, $max);
	}

	private function FunctionRandString($args)
	{
		$ar = $this->ArrgsToArray($args);
		$len = (int)array_shift($ar);

		return \randString($len);
	}

	private function FunctionRound($args)
	{
		$ar = $this->ArrgsToArray($args);
		$val = (float)array_shift($ar);
		$precision = (int)array_shift($ar);

		return round($val, $precision);
	}

	private function FunctionCeil($num)
	{
		return ceil($num);
	}

	private function FunctionFloor($num)
	{
		return floor($num);
	}

	private function FunctionNot($arg)
	{
		return !((boolean) $arg);
	}

	private function FunctionOr($args)
	{
		if (!is_array($args))
			return (boolean) $args;

		$args = $this->ArrgsToArray($args);
		foreach ($args as $arg)
		{
			if ($arg)
				return true;
		}

		return false;
	}

	private function FunctionSubstr($args)
	{
		if (!is_array($args))
			$args = array($args);

		$ar = $this->ArrgsToArray($args);
		$str = array_shift($ar);
		$pos = array_shift($ar);
		$len = array_shift($ar);

		if (($str == null) || ($str === ""))
			return null;

		if ($pos == null)
			$pos = 0;

		if ($len != null)
			return substr($str, $pos, $len);

		return substr($str, $pos);
	}

	private function FunctionStrpos($args)
	{
		$ar = $this->ArrgsToArray($args);
		$haystack = (string)array_shift($ar);
		$needle = (string)array_shift($ar);
		$offset = (int)array_shift($ar);

		return strpos($haystack, $needle, $offset);
	}

	private function FunctionStrlen($args)
	{
		$ar = $this->ArrgsToArray($args);
		$str = array_shift($ar);

		if (!is_scalar($str))
		{
			return null;
		}

		$str = (string) $str;
		return strlen($str);
	}

	private function FunctionUrlencode($args)
	{
		$ar = $this->ArrgsToArray($args);
		$str = array_shift($ar);

		if (!is_scalar($str))
		{
			if (is_array($str))
			{
				$str = implode(", ", CBPHelper::MakeArrayFlat($str));
			}
			else
			{
				return null;
			}
		}

		$str = (string) $str;
		return urlencode($str);
	}

	private function FunctionConvert($args)
	{
		if (!is_array($args))
			$args = array($args);

		$ar = $this->ArrgsToArray($args);
		$val = array_shift($ar);
		$type = array_shift($ar);
		$attr = array_shift($ar);

		$type = strtolower($type);
		if ($type === 'printableuserb24')
		{
			$result = array();

			$users = CBPHelper::StripUserPrefix($val);
			if (!is_array($users))
				$users = array($users);

			foreach ($users as $userId)
			{
				$db = CUser::GetByID($userId);
				if ($ar = $db->GetNext())
				{
					$ix = randString(5);
					$attr = (!empty($attr) ? 'href="'.$attr.'"' : 'href="#" onClick="return false;"');
					$result[] = '<a class="feed-post-user-name" id="bp_'.$userId.'_'.$ix.'" '.$attr.' bx-post-author-id="'.$userId.'" bx-post-author-gender="'.$ar['PERSONAL_GENDER'].'" bx-tooltip-user-id="'.$userId.'">'.CUser::FormatName(CSite::GetNameFormat(false), $ar, false).'</a>';
				}
			}

			$result = implode(", ", $result);
		}
		elseif ($type == 'printableuser')
		{
			$result = array();

			$users = CBPHelper::StripUserPrefix($val);
			if (!is_array($users))
				$users = array($users);

			foreach ($users as $userId)
			{
				$db = CUser::GetByID($userId);
				if ($ar = $db->GetNext())
					$result[] = CUser::FormatName(CSite::GetNameFormat(false), $ar, false);
			}

			$result = implode(", ", $result);

		}
		else
		{
			$result = $val;
		}

		return $result;
	}

	private function FunctionTrue()
	{
		return true;
	}

	private function FunctionMerge($args)
	{
		if (!is_array($args))
			$args = array();

		foreach ($args as &$a)
		{
			$a = (array)$a;
		}
		return call_user_func_array('array_merge', $args);
	}

	// Operation priority
	private $arPriority = array(
		'('  => 0,   ')'  => 1,     ';'   => 2,   '=' => 3,     '<' => 3,   '>' => 3,
		'<=' => 3,   '>=' => 3,     '<>'  => 3,   '&' => 4,     '+' => 5,   '-' => 5,
		'*'  => 6,   '/'  => 6,     '^'   => 7,   '%' => 8,     '-m' => 9,  '+m' => 9,
		' '  => 10,  ':'  => 11,    'f'   => 12,
	);

	// Allowable functions
	private $arAvailableFunctions = array(
		'abs' => array('args' => true, 'func' => 'FunctionAbs'),
		'and' => array('args' => true, 'func' => 'FunctionAnd'),
		'date' => array('args' => true, 'func' => 'FunctionDate'),
		'dateadd' => array('args' => true, 'func' => 'FunctionDateAdd'),
		'datediff' => array('args' => true, 'func' => 'FunctionDateDiff'),
		'false' => array('args' => false, 'func' => 'FunctionFalse'),
		'if' => array('args' => true, 'func' => 'FunctionIf'),
		'intval' => array('args' => true, 'func' => 'FunctionIntval'),
		'floatval' => array('args' => true, 'func' => 'FunctionFloatval'),
		'numberformat' => array('args' => true, 'func' => 'FunctionNumberFormat'),
		'min' => array('args' => true, 'func' => 'FunctionMin'),
		'max' => array('args' => true, 'func' => 'FunctionMax'),
		'rand' => array('args' => true, 'func' => 'FunctionRand'),
		'round' => array('args' => true, 'func' => 'FunctionRound'),
		'ceil' => array('args' => true, 'func' => 'FunctionCeil'),
		'floor' => array('args' => true, 'func' => 'FunctionFloor'),
		'not' => array('args' => true, 'func' => 'FunctionNot'),
		'or' => array('args' => true, 'func' => 'FunctionOr'),
		'substr' => array('args' => true, 'func' => 'FunctionSubstr'),
		'strpos' => array('args' => true, 'func' => 'FunctionStrpos'),
		'strlen' => array('args' => true, 'func' => 'FunctionStrlen'),
		'randstring' => array('args' => true, 'func' => 'FunctionRandString'),
		'true' => array('args' => false, 'func' => 'FunctionTrue'),
		'convert' => array('args' => true, 'func' => 'FunctionConvert'),
		'merge' => array('args' => true, 'func' => 'FunctionMerge'),
		'addworkdays' => array('args' => true, 'func' => 'FunctionAddWorkDays'),
		'workdateadd' => array('args' => true, 'func' => 'FunctionWorkDateAdd'),
		'isworkday' => array('args' => true, 'func' => 'FunctionIsWorkDay'),
		'isworktime' => array('args' => true, 'func' => 'FunctionIsWorkTime'),
		'urlencode' => array('args' => true, 'func' => 'FunctionUrlencode'),
	);

	// Allowable errors
	private $arAvailableErrors = array(
		0 => 'Incorrect variable name - "#STR#"',
		1 => 'Empty',
		2 => 'Syntax error "#STR#"',
		3 => 'Unknown function "#STR#"',
		4 => 'Unmatched closing bracket ")"',
		5 => 'Unmatched opening bracket "("',
		6 => 'Division by zero',
		7 => 'Incorrect order of operands',
		8 => 'Incorrect arguments of function "#STR#"',
	);

	const Operation = 0;
	const Variable = 1;
	const Constant = 2;
}

Zerion Mini Shell 1.0