<?php
/**
* datatypes.php iCalendar data type classes
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @copyright Copyright (C) 2008 Nigel Swinson, hide@address.com
* @author Nigel Swinson
* @package PhpiCalLib
* @version 1.0
*/
require_once 'exceptions.php';
$iPhpiCalLib_DataTypeIndex = 1;
define('PHPICALLIB_DATATYPE_XTYPE', $iPhpiCalLib_DataTypeIndex++);
define('PHPICALLIB_DATATYPE_IANATYPE', $iPhpiCalLib_DataTypeIndex++);
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08
// 3.3. Property Value Data Types . . . . . . . . . . . . . . . . 30
// 3.3.1. Binary . . . . . . . . . . . . . . . . . . . . . . . 31
define('PHPICALLIB_DATATYPE_BINARY', $iPhpiCalLib_DataTypeIndex++);
// 3.3.2. Boolean . . . . . . . . . . . . . . . . . . . . . . . 31
define('PHPICALLIB_DATATYPE_BOOLEAN', $iPhpiCalLib_DataTypeIndex++);
// 3.3.3. Calendar User Address . . . . . . . . . . . . . . . . 32
define('PHPICALLIB_DATATYPE_CAL_ADDRESS', $iPhpiCalLib_DataTypeIndex++);
// 3.3.4. Date . . . . . . . . . . . . . . . . . . . . . . . . 32
define('PHPICALLIB_DATATYPE_DATE', $iPhpiCalLib_DataTypeIndex++);
// 3.3.5. Date-Time . . . . . . . . . . . . . . . . . . . . . . 33
define('PHPICALLIB_DATATYPE_DATE_TIME', $iPhpiCalLib_DataTypeIndex++);
// 3.3.6. Duration . . . . . . . . . . . . . . . . . . . . . . 36
define('PHPICALLIB_DATATYPE_DURATION', $iPhpiCalLib_DataTypeIndex++);
// 3.3.7. Float . . . . . . . . . . . . . . . . . . . . . . . . 37
define('PHPICALLIB_DATATYPE_FLOAT', $iPhpiCalLib_DataTypeIndex++);
// 3.3.8. Integer . . . . . . . . . . . . . . . . . . . . . . . 37
define('PHPICALLIB_DATATYPE_INTEGER', $iPhpiCalLib_DataTypeIndex++);
// 3.3.9. Period of Time . . . . . . . . . . . . . . . . . . . 38
define('PHPICALLIB_DATATYPE_PERIOD', $iPhpiCalLib_DataTypeIndex++);
// 3.3.10. Recurrence Rule . . . . . . . . . . . . . . . . . . . 39
define('PHPICALLIB_DATATYPE_RECUR', $iPhpiCalLib_DataTypeIndex++);
// 3.3.11. Text . . . . . . . . . . . . . . . . . . . . . . . . 46
define('PHPICALLIB_DATATYPE_TEXT', $iPhpiCalLib_DataTypeIndex++);
// 3.3.12. Time . . . . . . . . . . . . . . . . . . . . . . . . 48
define('PHPICALLIB_DATATYPE_TIME', $iPhpiCalLib_DataTypeIndex++);
// 3.3.13. URI . . . . . . . . . . . . . . . . . . . . . . . . . 50
define('PHPICALLIB_DATATYPE_URI', $iPhpiCalLib_DataTypeIndex++);
// 3.3.14. UTC Offset . . . . . . . . . . . . . . . . . . . . . 50
define('PHPICALLIB_DATATYPE_UTC_OFFSET', $iPhpiCalLib_DataTypeIndex++);
/**
* Base class for all PhpiCalLib data types
*
*/
class PhpiCalLib_DataType {
protected $DataType = 0;
/**
* Regex to capture validate an iana-token
* @link http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.1
* iana-token = 1*(ALPHA / DIGIT / "-")
*
* @var string
*/
public static $IanaTokenRegex = '[a-zA-Z0-9-]+';
/**
* Map a data type id to it's string name.
*
* @var array Keyed by PHPICALLIB_DATATYPE_?, value is a string
*/
public static $TypeMap = array(
PHPICALLIB_DATATYPE_BINARY => 'BINARY',
PHPICALLIB_DATATYPE_BOOLEAN => 'BOOLEAN',
PHPICALLIB_DATATYPE_CAL_ADDRESS => 'CAL-ADDRESS',
PHPICALLIB_DATATYPE_DATE => 'DATE',
PHPICALLIB_DATATYPE_DATE_TIME => 'DATE-TIME',
PHPICALLIB_DATATYPE_DURATION => 'DURATION',
PHPICALLIB_DATATYPE_FLOAT => 'FLOAT',
PHPICALLIB_DATATYPE_INTEGER => 'INTEGER',
PHPICALLIB_DATATYPE_PERIOD => 'PERIOD',
PHPICALLIB_DATATYPE_RECUR => 'RECUR',
PHPICALLIB_DATATYPE_TEXT => 'TEXT',
PHPICALLIB_DATATYPE_TIME => 'TIME',
PHPICALLIB_DATATYPE_URI => 'URI',
PHPICALLIB_DATATYPE_UTC_OFFSET => 'UTC-OFFSET');
// array_flip() on $TypeMap, built on first use.
private static $ReverseTypeMap = null;
/**
* Convert a data type name to it's defined type
*
* @param string $Name a "name" RFC2445 token
* @return int one of the PHPICALLIB_DATATYPE_* values
*/
static public function ToDataType($Name) {
// Build the type map on first access
if (!self::$ReverseTypeMap) {
self::$ReverseTypeMap = array_flip(self::$TypeMap);
}
// If we have a key for this name, return the unique type
if (isset(self::$ReverseTypeMap[$Name])) {
return self::$ReverseTypeMap[$Name];
}
// It must be an iana defined extension or x-prop that we don't really recognize.
if (preg_match('/^X-.*$/', $Name)) {
return PHPICALLIB_DATATYPE_XTYPE;
}
return PHPICALLIB_PROPERTY_IANATYPE;
}
/**
* Convert a data type to it's defined name
*
* @param integer $Type one of the PHPICALLIB_DATATYPE_* values
* @return string A "name" RFC2445 token
*/
static public function FromDataType($Type) {
if (empty(self::$TypeMap[$Type])) return '';
return self::$TypeMap[$Type];
}
}
/**
* The date data type.
* <pre>
* date = date-value
*
* date-value = date-fullyear date-month date-mday
* date-fullyear = 4DIGIT
* date-month = 2DIGIT ;01-12
* date-mday = 2DIGIT ;01-28, 01-29, 01-30, 01-31
* </pre>
* @link http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.3.4
*/
class PhpiCalLib_DataTypes_Date extends PhpiCalLib_DataType {
// The data
private $Data = array(
'Year' => 0,
'Month' => 1,
'MonthDay' => 1);
/**
* Constructor
*
*/
public function __construct() {
$this->DataType = PHPICALLIB_DATATYPE_DATE;
}
/**
* Set the date-fullyear component of the date-value
*
* @param number $Number
*/
public function SetFullYear($Number) {
// Do a string check
$Pattern = '/^\d?\d?\d?\d$/D';
if (!preg_match($Pattern, $Number)) {
throw new PhpiCalLib_ParameterException(sprintf("Invalid date-fullyear (%s) value: %d", $Pattern, $Number));
}
$this->Data['Year'] = $Number;
}
/**
* Access the date-fullyear
*
* @return integer
*/
public function GetFullYear() {
return $this->Data['Year'];
}
/**
* Set the date-fullyear component of the date-value
*
* @param number $Number A number of years since 1900
*/
public function SetYear($Number) {
if (!is_numeric($Number)) {
throw new PhpiCalLib_ParameterException(sprintf("Invalid non integer date-fullyear value: %d", $Number));
}
$this->SetFullYear($Number + 1900);
}
/**
* Set the date-month component of the date-value
*
* @param number $Number
*/
public function SetMonth($Number) {
// Must be numeric
$this->DigitCheck($Number, 'date-month', 1, 12);
$this->Data['Month'] = $Number;
}
/**
* Access the date-month
*
* @return integer
*/
public function GetMonth() {
return $this->Data['Month'];
}
/**
* Set the date-mday component of the date-value
*
* @param number $Number
*/
public function SetMonthDay($Number) {
// Must be numeric
$this->DigitCheck($Number, 'date-mday', 1, 31);
$this->Data['MonthDay'] = $Number;
}
/**
* Access the date-mday
*
* @return integer
*/
public function GetMonthDay() {
return $this->Data['MonthDay'];
}
/**
* Decode a timestamp to an array of values like localtime() does, but with support for UTC
*
* @param integer $TimeStamp A unix timestamp
* @param bool $Utc true to extract the date WRT to utc, false to extract the "local time"
*/
static public function DecodeTimeStamp($TimeStamp, $Utc) {
// If we have to extract the local date
if (!$Utc) {
// Then it's easy
return localtime($TimeStamp);
}
$aTime = array();
{
// Else as timestamps are always WRT to UTC, in order to use the localtime() to decode,
// we temporarily set the local timezone to UTC
$TimeZone = date_default_timezone_get();
try {
date_default_timezone_set('UTC');
$aTime = localtime($TimeStamp);
} catch (Exception $E) {
date_default_timezone_set($TimeZone);
throw $E;
}
date_default_timezone_set($TimeZone);
}
return $aTime;
}
/**
* Extract the date from the given timestamp
*
* @param integer $TimeStamp Unix epoch WRT to UTC
* @param bool $Utc true to extract the date WRT to utc, false to extract the "local time"
* */
public function FromTimeStamp($TimeStamp, $Utc) {
$aTime = self::DecodeTimeStamp($TimeStamp, $Utc);
// Set the attributes
$this->SetMonthDay($aTime[3]);
$this->SetMonth($aTime[4] + 1);
$this->SetYear($aTime[5]);
}
/**
* Return the date WRT to midnight, UTC
*
* @return integer Seconds since January 1 1970 00:00:00 GMT
*/
public function ToTimeStamp() {
// int gmmktime ( [int hour [, int minute [, int second [, int month [, int day [, int year [, int is_dst]]]]]]] )
return gmmktime(0,0,0,$this->Data['Month'], $this->Data['MonthDay'], $this->Data['Year']);
}
/**
* Check that the Number matches 2DIGIT and is in range
*
* @param string $Number The proposed number
* @param string $TokenName
* @param integer $MinValue The minimum legitimate value
* @param integer $MaxValue The maximum legitimate value
*/
public static function DigitCheck($Number, $TokenName, $MinValue, $MaxValue) {
// Do a string check
$Pattern = '/^\d?\d$/D';
if (!preg_match($Pattern, $Number)) {
throw new PhpiCalLib_ParameterException(sprintf("Invalid %s (%s) value: %d", $TokenName, $Pattern, $Number));
}
if ($Number < $MinValue) {
throw new PhpiCalLib_ParameterException(sprintf("Invalid %s value, must be larger than %d: %d", $TokenName, $MinValue, $Number));
}
if ($Number > $MaxValue) {
throw new PhpiCalLib_ParameterException(sprintf("Invalid %s value, must be less than %d: %d", $TokenName, $MaxValue, $Number));
}
}
/**
* Extract the date value from the encoded string
*
* @param string $EncodedString
*/
public function Parse($EncodedString) {
// date = date-value
//
// date-value = date-fullyear date-month date-mday
// date-fullyear = 4DIGIT
// date-month = 2DIGIT ;01-12
// date-mday = 2DIGIT ;01-28, 01-29, 01-30, 01-31
$Pattern = '/^(\d\d\d\d)(\d\d)(\d\d)$/';
$aMatches = array();
if (!preg_match($Pattern, $EncodedString, $aMatches)) {
throw new PhpiCalLib_ParameterException(sprintf("Invalid date (%s) in: %s", $Pattern, $EncodedString));
}
$this->SetFullYear($aMatches[1]);
$this->SetMonth($aMatches[2]);
$this->SetMonthDay($aMatches[3]);
}
/**
* Convert to string
*
* @return string
*/
public function ToString() {
return sprintf("%04d%02d%02d", $this->Data['Year'], $this->Data['Month'], $this->Data['MonthDay']);
}
}
/**
* The date-time data type.
* <pre>
* date-time = date "T" time ;As specified in the date and time
* ;value definitions
* </pre>
* @link http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.3.5
*/
class PhpiCalLib_DataTypes_DateTime extends PhpiCalLib_DataType {
private $Time = null;
private $Date = null;
public function __construct() {
$this->Type = PHPICALLIB_DATATYPE_DATE_TIME;
$this->Time = new PhpiCalLib_DataTypes_Time();
$this->Date = new PhpiCalLib_DataTypes_Date();
}
/**
* @return PhpiCalLib_DataTypes_Date
*/
public function GetDate() {
return $this->Date;
}
/**
* @param PhpiCalLib_DataTypes_Date $Date
*/
public function SetDate($Date) {
$this->Date = $Date;
}
/**
* @return PhpiCalLib_DataTypes_Time
*/
public function GetTime() {
return $this->Time;
}
/**
* @param PhpiCalLib_DataTypes_Time $Time
*/
public function SetTime($Time) {
$this->Time = $Time;
}
/**
* Return the time WRT to midnight Jan 1st 1970, UTC
*
* @return integer Seconds since January 1 1970 00:00:00 GMT
*/
public function ToTimeStamp() {
return $this->Time->ToTimeStamp() + $this->Date->ToTimeStamp();
}
/**
* Set the time from a unix timestamp
*
* @param number $Time
* @param bool $Utc true to store in utc, false to store in "floating time", TZ specified by the TZID parameter
*/
public function FromTimeStamp($Time, $Utc) {
$aTime = PhpiCalLib_DataTypes_Date::DecodeTimeStamp($Time, $Utc);
$this->Time->SetSeconds($aTime[0]);
$this->Time->SetMinutes($aTime[1]);
$this->Time->SetHours($aTime[2]);
$this->Time->SetUtc($Utc);
$this->Date->SetMonthDay($aTime[3]);
$this->Date->SetMonth($aTime[4] + 1);
$this->Date->SetYear($aTime[5]);
}
/**
* Extract the date-time value from the encoded string
*
* @param string $EncodedString
*/
public function Parse($EncodedString) {
// date-time = date "T" time ;As specified in the date and time
// ;value definitions
$Pattern = '/^(.*)T(.*)$/';
$aMatches = array();
if (!preg_match($Pattern, $EncodedString, $aMatches)) {
throw new PhpiCalLib_ParameterException(sprintf("Invalid date-time (%s) in: %s", $Pattern, $EncodedString));
}
$this->Date->Parse($aMatches[1]);
$this->Time->Parse($aMatches[2]);
}
/**
* Convert to string
*
* @return string
*/
public function ToString() {
return sprintf("%sT%s", $this->Date->ToString(), $this->Time->ToString());
}
}
/**
* The dur-value data type.
* <pre>
* dur-value = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
*
* dur-date = dur-day [dur-time]
* dur-time = "T" (dur-hour / dur-minute / dur-second)
* dur-week = 1*DIGIT "W"
* dur-hour = 1*DIGIT "H" [dur-minute]
* dur-minute = 1*DIGIT "M" [dur-second]
* dur-second = 1*DIGIT "S"
* dur-day = 1*DIGIT "D"
* </pre>
* @link http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.3.6
*/
class PhpiCalLib_DataTypes_Duration extends PhpiCalLib_DataType {
private $Polarity = 1;
private $Data = array();
/**
* Constructor
*
*/
public function __construct() {
$this->DataType = PHPICALLIB_DATATYPE_DURATION;
}
/**
* Set the dur-second component of the dur-value
*
* @param number $Number
*/
public function SetSeconds($Number) {
// Must be numeric
$this->DigitCheck($Number, 'dur-second');
$this->Data['Second'] = $Number;
// This also unsets the weeks
unset($this->Data['Week']);
}
/**
* Access the dur-second
*
* @return integer
*/
public function GetSeconds() {
if (!isset($this->Data['Second'])) return 0;
return $this->Data['Second'];
}
/**
* Set the dur-minute component of the dur-value
*
* @param number $Minutes
*/
public function SetMinutes($Number) {
// Must be numeric
$this->DigitCheck($Number, 'dur-minute');
$this->Data['Minute'] = $Number;
// This also unsets the weeks
unset($this->Data['Week']);
}
/**
* Access the dur-minute
*
* @return integer
*/
public function GetMinutes() {
if (!isset($this->Data['Minute'])) return 0;
return $this->Data['Minute'];
}
/**
* Set the dur-hour component of the dur-value
*
* @param number $Hours
*/
public function SetHours($Number) {
// Must be numeric
$this->DigitCheck($Number, 'dur-hour');
$this->Data['Hour'] = $Number;
// This also unsets the weeks
unset($this->Data['Week']);
}
/**
* Access the dur-hour
*
* @return integer
*/
public function GetHours() {
if (!isset($this->Data['Hour'])) return 0;
return $this->Data['Hour'];
}
/**
* Set the dur-day component of the dur-value
*
* @param number $Days
*/
public function SetDays($Number) {
// Must be numeric
$this->DigitCheck($Number, 'dur-day');
$this->Data['Day'] = $Number;
// This also unsets the weeks
unset($this->Data['Week']);
}
/**
* Access the dur-day
*
* @return integer
*/
public function GetDays() {
if (!isset($this->Data['Day'])) return 0;
return $this->Data['Day'];
}
/**
* Set the dur-week component of the dur-value
*
* @param number $Week
*/
public function SetWeeks($Number) {
// Must be numeric
$this->DigitCheck($Number, 'dur-week');
$this->Data['Week'] = $Number;
// This also unsets the other attributes
unset($this->Data['Day']);
unset($this->Data['Hour']);
unset($this->Data['Minute']);
unset($this->Data['Second']);
}
/**
* Access the dur-week
*
* @return integer
*/
public function GetWeeks() {
if (!isset($this->Data['Week'])) return 0;
return $this->Data['Week'];
}
/**
* @return bool
*/
public function GetPolarity() {
return $this->Polarity;
}
/**
* @param bool $Polarity
*/
public function SetPolarity($Polarity) {
$this->Polarity = ($Polarity != false);
}
/**
* Check that the Number matches 1*DIGIT
*
* @param string $Number The proposed number
* @param string $TokenName
*/
private function DigitCheck($Number, $TokenName) {
// If it's an integer, it's automatically safe
if (is_int($Number)) {
if ($Number < 0) {
throw new PhpiCalLib_ParameterException(sprintf("Invalid %s (negative) value: %d", $TokenName, $Number));
}
return;
}
// Do a string check
$Pattern = '/^\d+$/D';
if (!preg_match($Pattern, $Number)) {
throw new PhpiCalLib_ParameterException(sprintf("Invalid %s (%s) value: %d", $TokenName, $Pattern, $Number));
}
}
/**
* Convert to string
*
* @return string
*/
public function ToString() {
$Result = '';
// Start with polarity
$Result .= ($this->Polarity ? '' : '-');
$Result .= 'P';
// First preference is weeks
if (!empty($this->Data['Week'])) {
return sprintf("%s%dW", $Result, $this->Data['Week']);
}
// Next add days
if (!empty($this->Data['Day'])) {
$Result .= sprintf("%dD",$this->Data['Day']);
// If there's no time, we're done.
if (empty($this->Data['Hour'])
&& empty($this->Data['Minute'])
&& empty($this->Data['Second'])) {
// Return the duration in days
return $Result;
}
}
// Next add time
$Result .= 'T';
if (!empty($this->Data['Hour'])) {
$Result .= sprintf("%dH",$this->Data['Hour']);
}
if (!empty($this->Data['Minute'])) {
$Result .= sprintf("%dM",$this->Data['Minute']);
}
if (!empty($this->Data['Second'])) {
$Result .= sprintf("%dS",$this->Data['Second']);
}
// Check we aren't about to return an empty string
if ($Result == 'PT') $Result .= '0S';
// All done!
return $Result;
}
}
/**
* The text data type.
* <pre>
* text = *(TSAFE-CHAR / ":" / DQUOTE / ESCAPED-CHAR)
* ; Folded according to description above
*
* ESCAPED-CHAR = ("\\" / "\;" / "\," / "\N" / "\n")
* ; \\ encodes \, \N or \n encodes newline
* ; \; encodes ;, \, encodes ,
*
* TSAFE-CHAR = %x20-21 / %x23-2B / %x2D-39 / %x3C-5B /
* %x5D-7E / NON-US-ASCII
* ; Any character except CTLs not needed by the current
* ; character set, DQUOTE, ";", ":", "\", ","
* </pre>
* @link http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.3.11
*/
class PhpiCalLib_DataTypes_Text extends PhpiCalLib_DataType {
/**
* The text value
*
* @var string
*/
private $Value = '';
/**
* Constructor
*
*/
public function __construct() {
$this->DataType = PHPICALLIB_DATATYPE_TEXT;
}
/**
* Set the value
*
* @param string $Text
*/
public function SetValue($Text) {
//http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.3.11
// text = *(TSAFE-CHAR / ":" / DQUOTE / ESCAPED-CHAR)
// ; Folded according to description above
//
// ESCAPED-CHAR = ("\\" / "\;" / "\," / "\N" / "\n")
// ; \\ encodes \, \N or \n encodes newline
// ; \; encodes ;, \, encodes ,
//
// TSAFE-CHAR = %x20-21 / %x23-2B / %x2D-39 / %x3C-5B /
// %x5D-7E / NON-US-ASCII
// ; Any character except CTLs not needed by the current
// ; character set, DQUOTE, ";", ":", "\", ","
// Due to the quoting, this means that you can represent these characters:
// text = *(%x20-21 / %x23-2B / %x2D-39 / %x3C-5B /
// %x5D-7E / %x3A / %x22 / %x5C / %3B / %x2C / %x0A)
// text = *(%x0A / %x20-21 / %x22 /%x23-2B / %x2C /%x2D-39 / %x3A / %3B /
// %x3C-5B / %x5C / %x5D-7E )
// text = *(%x0A / %x20-7E )
// And I'm going to add \t, as I think that was meant too
$Pattern = '/^[\x09\x0A\x20-\x7E]*$/D';
if (!preg_match($Pattern, $Text)) {
$aTokens = preg_split('/[^\x09\x0A\x20-\x7E]/', $Text, -1, PREG_SPLIT_NO_EMPTY);
throw new PhpiCalLib_ParameterException(sprintf('Invalid text (%s) token, invalid chars between \'%s\': %s',
$Pattern, implode(',',$aTokens), $Text));
}
$this->Value = $Text;
}
/**
* Access the unescaped text value
*
* @return string
*/
public function GetValue() {
return $this->Value;
}
/**
* Extract the text value from the encoded string
*
* @param string $EncodedString
*/
public function Parse($EncodedString) {
// Check it matches the text syntax
// Note I've added support for \x09, \t and \", which aren't strictly in the spec
$Pattern = '/^([\x09\x20-\x21\x23-\x2B\x2D-\x39\x3C-\x5B\x5D-\x7E:"]|\\\\\\\\|\\\\;|\\\\,|\\\\N|\\\\n|\\\\t|\\\\")*$/D';
if (!preg_match($Pattern, $EncodedString)) {
// It make have contained some escaped chars.
$aTokens = preg_split('/[^\x09\x20-\x21\x23-\x2B\x2D-\x39\x3C-\x5B\x5D-\x7E:"]/', $EncodedString, -1, PREG_SPLIT_NO_EMPTY);
throw new PhpiCalLib_ParseException(sprintf("Invalid text (%s) token between these tokens '%s' in: %s", $Pattern, implode("','", $aTokens), $EncodedString));
}
// Extract the text-value
$TextValue = $EncodedString;
$TextValue = str_replace('\\t', "\t",$TextValue);
$TextValue = str_replace('\"', '"',$TextValue);
$TextValue = str_replace("\\n", "\n",$TextValue);
$TextValue = str_replace("\\N", "\n",$TextValue);
$TextValue = str_replace("\\,", ",",$TextValue);
$TextValue = str_replace("\\;", ";",$TextValue);
$TextValue = str_replace("\\\\", "\\",$TextValue);
$this->Value = $TextValue;
}
/**
* Convert to an encoded string
*
* @return string
*/
public function ToString() {
// Encode to a "value" token
$Text = $this->Value;
$Text = str_replace("\\", "\\\\",$Text);
$Text = str_replace("\n", "\\n",$Text);
$Text = str_replace(",", "\\,",$Text);
$Text = str_replace(";", "\\;",$Text);
return $Text;
}
}
/**
* The time data type.
* <pre>
* time = time-hour time-minute time-second [time-utc]
*
* time-hour = 2DIGIT ;00-23
* time-minute = 2DIGIT ;00-59
* time-second = 2DIGIT ;00-60
* ;The "60" value is used to account for positive "leap" seconds.
*
* time-utc = "Z"
* @link http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-08#section-3.3.12
*/
class PhpiCalLib_DataTypes_Time extends PhpiCalLib_DataType {
// If this object is in Utc
private $Utc = false;
// The data
private $Data = array(
'Hour' => 0,
'Minute' => 0,
'Second' => 0);
/**
* Constructor
*
*/
public function __construct() {
$this->DataType = PHPICALLIB_DATATYPE_TIME;
}
/**
* Set the time-second component of the time
*
* @param number $Number
*/
public function SetSeconds($Number) {
// Must be numeric
PhpiCalLib_DataTypes_Date::DigitCheck($Number, 'time-second', 0, 60);
$this->Data['Second'] = (int)$Number;
}
/**
* Access the number of seconds
*
* @return integer
*/
public function GetSeconds() {
return (int)$this->Data['Second'];
}
/**
* Set the time-minute component of the time
*
* @param number $Number
*/
public function SetMinutes($Number) {
// Must be numeric
PhpiCalLib_DataTypes_Date::DigitCheck($Number, 'time-minute', 0, 59);
$this->Data['Minute'] = $Number;
}
/**
* Access the number of minutes
*
* @return integer
*/
public function GetMinutes() {
return $this->Data['Minute'];
}
/**
* Set the time-hour component of the time
*
* @param number $Number
*/
public function SetHours($Number) {
// Must be numeric
PhpiCalLib_DataTypes_Date::DigitCheck($Number, 'time-hour', 0, 23);
$this->Data['Hour'] = $Number;
}
/**
* Access the number of hours
*
* @return integer
*/
public function GetHours() {
return $this->Data['Hour'];
}
/**
* Set the time-utc component of the time
*
* @param bool $value True for Utc, else false
*/
public function SetUtc($value) {
$this->Utc = ($value != false);
}
/**
* Determine if the time is UTC or floating/local
*
* @return bool
*/
public function GetUtc() {
return $this->Utc;
}
/**
* Extract the date from the given timestamp
*
* @param integer $TimeStamp Unix epoch WRT to UTC
* @param bool $Utc true to extract the date WRT to utc, false to extract the "local time"
* */
public function FromTimeStamp($TimeStamp, $Utc) {
$aTime = PhpiCalLib_DataTypes_Date::DecodeTimeStamp($TimeStamp, $Utc);
// Set the attributes
$this->SetSeconds($aTime[0]);
$this->SetMinutes($aTime[1]);
$this->SetHours($aTime[2]);
$this->SetUtc($Utc);
}
/**
* Return the seconds from midnight on the same day
*
* @return integer Seconds since January 1 1970 00:00:00 GMT
*/
public function ToTimeStamp() {
// int gmmktime ( [int hour [, int minute [, int second [, int month [, int day [, int year [, int is_dst]]]]]]] )
return gmmktime($this->Data['Hour'],$this->Data['Minute'],$this->Data['Second'],1,1,1970);
}
/**
* Extract the date-time value from the encoded string
*
* @param string $EncodedString
*/
public function Parse($EncodedString) {
// time = time-hour time-minute time-second [time-utc]
// time-hour = 2DIGIT ;00-23
// time-minute = 2DIGIT ;00-59
// time-second = 2DIGIT ;00-60
// time-utc = "Z"
$Pattern = '/^(\d\d)(\d\d)(\d\d)(Z?)$/';
$aMatches = array();
if (!preg_match($Pattern, $EncodedString, $aMatches)) {
throw new PhpiCalLib_ParameterException(sprintf("Invalid date-time (%s) in: %s", $Pattern, $EncodedString));
}
$this->SetHours($aMatches[1]);
$this->SetMinutes($aMatches[2]);
$this->SetSeconds($aMatches[3]);
$this->SetUtc(!empty($aMatches[4]));
}
/**
* Convert to string
*
* @return string
*/
public function ToString() {
return sprintf("%02d%02d%02d%s", $this->Data['Hour'], $this->Data['Minute'], $this->Data['Second'], $this->Utc ? 'Z' : '');
}
}
?>