summaryrefslogtreecommitdiffstats
path: root/lib/SimpleSAML/Utils/Time.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/SimpleSAML/Utils/Time.php')
-rw-r--r--lib/SimpleSAML/Utils/Time.php162
1 files changed, 162 insertions, 0 deletions
diff --git a/lib/SimpleSAML/Utils/Time.php b/lib/SimpleSAML/Utils/Time.php
new file mode 100644
index 0000000..9898f8b
--- /dev/null
+++ b/lib/SimpleSAML/Utils/Time.php
@@ -0,0 +1,162 @@
+<?php
+/**
+ * Time-related utility methods.
+ *
+ * @package SimpleSAMLphp
+ */
+
+namespace SimpleSAML\Utils;
+
+
+class Time
+{
+
+ /**
+ * This function generates a timestamp on the form used by the SAML protocols.
+ *
+ * @param int $instant The time the timestamp should represent. Defaults to current time.
+ *
+ * @return string The timestamp.
+ * @author Olav Morken, UNINETT AS <olav.morken@uninett.no>
+ */
+ public static function generateTimestamp($instant = null)
+ {
+ if ($instant === null) {
+ $instant = time();
+ }
+ return gmdate('Y-m-d\TH:i:s\Z', $instant);
+ }
+
+
+ /**
+ * Initialize the timezone.
+ *
+ * This function should be called before any calls to date().
+ *
+ * @author Olav Morken, UNINETT AS <olav.morken@uninett.no>
+ */
+ public static function initTimezone()
+ {
+ static $initialized = false;
+
+ if ($initialized) {
+ return;
+ }
+
+ $initialized = true;
+
+ $globalConfig = \SimpleSAML_Configuration::getInstance();
+
+ $timezone = $globalConfig->getString('timezone', null);
+ if ($timezone !== null) {
+ if (!date_default_timezone_set($timezone)) {
+ throw new \SimpleSAML_Error_Exception('Invalid timezone set in the "timezone" option in config.php.');
+ }
+ return;
+ }
+ // we don't have a timezone configured
+
+ /*
+ * The date_default_timezone_get() function is likely to cause a warning.
+ * Since we have a custom error handler which logs the errors with a backtrace,
+ * this error will be logged even if we prefix the function call with '@'.
+ * Instead we temporarily replace the error handler.
+ */
+ set_error_handler(function () {
+ return true;
+ });
+ $serverTimezone = date_default_timezone_get();
+ restore_error_handler();
+
+ // set the timezone to the default
+ date_default_timezone_set($serverTimezone);
+ }
+
+
+ /**
+ * Interpret a ISO8601 duration value relative to a given timestamp.
+ *
+ * @param string $duration The duration, as a string.
+ * @param int $timestamp The unix timestamp we should apply the duration to. Optional, default to the current
+ * time.
+ *
+ * @return int The new timestamp, after the duration is applied.
+ * @throws \InvalidArgumentException If $duration is not a valid ISO 8601 duration or if the input parameters do
+ * not have the right data types.
+ */
+ public static function parseDuration($duration, $timestamp = null)
+ {
+ if (!(is_string($duration) && (is_int($timestamp) || is_null($timestamp)))) {
+ throw new \InvalidArgumentException('Invalid input parameters');
+ }
+
+ // parse the duration. We use a very strict pattern
+ $durationRegEx = '#^(-?)P(?:(?:(?:(\\d+)Y)?(?:(\\d+)M)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)(?:[.,]\d+)?S)?)?)|(?:(\\d+)W))$#D';
+ if (!preg_match($durationRegEx, $duration, $matches)) {
+ throw new \InvalidArgumentException('Invalid ISO 8601 duration: '.$duration);
+ }
+
+ $durYears = (empty($matches[2]) ? 0 : (int) $matches[2]);
+ $durMonths = (empty($matches[3]) ? 0 : (int) $matches[3]);
+ $durDays = (empty($matches[4]) ? 0 : (int) $matches[4]);
+ $durHours = (empty($matches[5]) ? 0 : (int) $matches[5]);
+ $durMinutes = (empty($matches[6]) ? 0 : (int) $matches[6]);
+ $durSeconds = (empty($matches[7]) ? 0 : (int) $matches[7]);
+ $durWeeks = (empty($matches[8]) ? 0 : (int) $matches[8]);
+
+ if (!empty($matches[1])) {
+ // negative
+ $durYears = -$durYears;
+ $durMonths = -$durMonths;
+ $durDays = -$durDays;
+ $durHours = -$durHours;
+ $durMinutes = -$durMinutes;
+ $durSeconds = -$durSeconds;
+ $durWeeks = -$durWeeks;
+ }
+
+ if ($timestamp === null) {
+ $timestamp = time();
+ }
+
+ if ($durYears !== 0 || $durMonths !== 0) {
+ /* Special handling of months and years, since they aren't a specific interval, but
+ * instead depend on the current time.
+ */
+
+ /* We need the year and month from the timestamp. Unfortunately, PHP doesn't have the
+ * gmtime function. Instead we use the gmdate function, and split the result.
+ */
+ $yearmonth = explode(':', gmdate('Y:n', $timestamp));
+ $year = (int) ($yearmonth[0]);
+ $month = (int) ($yearmonth[1]);
+
+ // remove the year and month from the timestamp
+ $timestamp -= gmmktime(0, 0, 0, $month, 1, $year);
+
+ // add years and months, and normalize the numbers afterwards
+ $year += $durYears;
+ $month += $durMonths;
+ while ($month > 12) {
+ $year += 1;
+ $month -= 12;
+ }
+ while ($month < 1) {
+ $year -= 1;
+ $month += 12;
+ }
+
+ // add year and month back into timestamp
+ $timestamp += gmmktime(0, 0, 0, $month, 1, $year);
+ }
+
+ // add the other elements
+ $timestamp += $durWeeks * 7 * 24 * 60 * 60;
+ $timestamp += $durDays * 24 * 60 * 60;
+ $timestamp += $durHours * 60 * 60;
+ $timestamp += $durMinutes * 60;
+ $timestamp += $durSeconds;
+
+ return $timestamp;
+ }
+} \ No newline at end of file