aboutsummaryrefslogtreecommitdiff
path: root/lib/classes/Request.php
diff options
context:
space:
mode:
authorPhilipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de>2024-09-24 10:53:31 +0200
committerPhilipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de>2024-09-24 10:53:31 +0200
commit4459dd7917f4d1c34f40bb68f0e991e9c3d53e4c (patch)
tree5c07151ae61276d334e88f6309c30d439a85c12e /lib/classes/Request.php
parentda0022e5c1abbf9825ae76debaabdff7e8623bb4 (diff)
parent97a188592c679890a25c37ab78463add76a52ff7 (diff)
Merge branch 'main' into issue-3911issue-3911
Diffstat (limited to 'lib/classes/Request.php')
-rw-r--r--lib/classes/Request.php828
1 files changed, 828 insertions, 0 deletions
diff --git a/lib/classes/Request.php b/lib/classes/Request.php
new file mode 100644
index 0000000..d72a6a9
--- /dev/null
+++ b/lib/classes/Request.php
@@ -0,0 +1,828 @@
+<?php
+# Lifter007: TODO
+/*
+ * Request.php - class representing a HTTP request in Stud.IP
+ *
+ * Copyright (c) 2009 Elmar Ludwig
+ *
+ * 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.
+ */
+
+/**
+ * Singleton class representing a HTTP request in Stud.IP.
+ */
+class Request implements ArrayAccess, IteratorAggregate
+{
+ /**
+ * cached request parameter array
+ */
+ private $params;
+
+ /**
+ * Initialize a new Request instance.
+ */
+ private function __construct()
+ {
+ $this->params = array_merge($_GET, $_POST);
+ }
+
+ /**
+ * Return the Request singleton instance.
+ */
+ public static function getInstance()
+ {
+ static $instance;
+
+ if (isset($instance)) {
+ return $instance;
+ }
+
+ return $instance = new Request();
+ }
+
+ /**
+ * ArrayAccess: Check whether the given offset exists.
+ */
+ public function offsetExists($offset): bool
+ {
+ return isset($this->params[$offset]);
+ }
+
+ /**
+ * ArrayAccess: Get the value at the given offset.
+ */
+ public function offsetGet($offset): mixed
+ {
+ return $this->params[$offset] ?? null;
+ }
+
+ /**
+ * ArrayAccess: Set the value at the given offset.
+ */
+ public function offsetSet($offset, $value): void
+ {
+ $this->params[$offset] = $value;
+ }
+
+ /**
+ * ArrayAccess: Delete the value at the given offset.
+ */
+ public function offsetUnset($offset): void
+ {
+ unset($this->params[$offset]);
+ }
+
+ /**
+ * IteratorAggregate: Create iterator for request parameters.
+ */
+ public function getIterator(): Traversable
+ {
+ return new ArrayIterator((array)$this->params);
+ }
+
+ /**
+ * Return the current URL, including query parameters.
+ */
+ public static function url()
+ {
+ return self::protocol() . '://' . self::server() . self::path();
+ }
+
+ /**
+ * Return the current protocol ('http' or 'https').
+ */
+ public static function protocol()
+ {
+
+ // If a reverse proxy tells us the required protocol we should respect that
+ if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
+ return $_SERVER['HTTP_X_FORWARDED_PROTO'];
+ }
+
+ return (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
+ ? 'https'
+ : 'http';
+ }
+
+ /**
+ * Return the current server name and port (host:port).
+ */
+ public static function server()
+ {
+ $host = $_SERVER['SERVER_NAME'];
+ $port = $_SERVER['SERVER_PORT'];
+ $ssl = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on';
+
+ if ($ssl && $port != 443 || !$ssl && $port != 80) {
+ $host .= ':' . $port;
+ }
+
+ return $host;
+ }
+
+ /**
+ * Return the current request path, relative to the server root.
+ */
+ public static function path()
+ {
+ return $_SERVER['REQUEST_URI'];
+ }
+
+ /**
+ * Return the filename of the currently executing script.
+ * @return string
+ */
+ public static function scriptName(): string
+ {
+ return $_SERVER['SCRIPT_NAME'];
+ }
+
+ /**
+ * Returns the complete path info including duplicated slashes.
+ * $_SERVER['PATH_INFO'] will remove them.
+ */
+ public static function pathInfo(): string
+ {
+ $script_name = self::scriptName();
+ $script_name = preg_quote($script_name, '#');
+ $script_name = str_replace('/', '/+', $script_name);
+
+ $path_info = preg_replace(
+ "#^{$script_name}#",
+ '',
+ urldecode(self::path())
+ );
+ return parse_url($path_info, PHP_URL_PATH) ?? '';
+ }
+
+ /**
+ * Set the selected query parameter to a specific value.
+ *
+ * @param string $param parameter name
+ * @param mixed $value parameter value (string or array)
+ */
+ public static function set($param, $value)
+ {
+ $request = self::getInstance();
+
+ $request->params[$param] = $value;
+ }
+
+ /**
+ * Return the value of the selected query parameter as a string.
+ *
+ * @param string $param parameter name
+ * @param string $default default value if parameter is not set
+ *
+ * @return string parameter value as string (if set), else NULL
+ */
+ public static function get($param, $default = NULL)
+ {
+ $request = self::getInstance();
+
+ return (isset($request[$param]) && is_string($request[$param]))
+ ? $request[$param]
+ : $default;
+ }
+
+ /**
+ * Return the value of the selected query parameter as an I18NString.
+ *
+ * @param string $param parameter name
+ * @param string $default default value if parameter is not set
+ * @param Callable $op Operation to perform on each text string
+ *
+ * @return I18NString parameter value as string (if set), else NULL
+ */
+ public static function i18n($param, $default = NULL, Callable $op = null)
+ {
+ $value = self::get($param, $default);
+
+ if (isset($value)) {
+ $lang = self::getArray($param . '_i18n');
+
+ if ($op) {
+ $value = $op($value);
+ $lang = array_map($op, $lang);
+ }
+
+ $value = new I18NString($value, $lang);
+ }
+
+ return $value;
+ }
+
+ /**
+ * Return the value of the selected query parameter as a string.
+ * The contents of the string is quoted with addslashes().
+ *
+ * @param string $param parameter name
+ * @param string $default default value if parameter is not set
+ *
+ * @return string parameter value as string (if set), else NULL
+ */
+ public static function quoted($param, $default = NULL)
+ {
+ $value = self::get($param, $default);
+
+ if (isset($value)) {
+ $value = addslashes($value);
+ }
+
+ return $value;
+ }
+
+ /**
+ * Return the value of the selected query parameter as an alphanumeric
+ * string (consisting of only digits, letters and underscores).
+ *
+ * @param string $param parameter name
+ * @param string $default default value if parameter is not set
+ *
+ * @return string parameter value as string (if set), else NULL
+ */
+ public static function option($param, $default = NULL)
+ {
+ $value = self::get($param, $default);
+
+ if (!isset($value) || preg_match('/\\W/', $value)) {
+ $value = $default;
+ }
+
+ return $value;
+ }
+
+ /**
+ * Return the value of the selected query parameter as an integer.
+ *
+ * @param string $param parameter name
+ * @param int $default default value if parameter is not set
+ *
+ * @return int parameter value as integer (if set), else NULL
+ */
+ public static function int($param, $default = NULL)
+ {
+ $value = self::get($param, $default);
+
+ if (isset($value)) {
+ $value = (int) $value;
+ }
+
+ return $value;
+ }
+
+ /**
+ * Return the value of the selected query parameter as a float.
+ *
+ * @param string $param parameter name
+ * @param float $default default value if parameter is not set
+ *
+ * @return float parameter value as float (if set), else NULL
+ */
+ public static function float($param, $default = NULL)
+ {
+ $value = self::get($param, $default);
+
+ if (isset($value)) {
+ $value = (float) strtr($value, ',', '.');
+ }
+
+ return $value;
+ }
+
+
+ /**
+ * Returns the date and time values from one or two fields
+ * as a DateTime object. The $second_param and $second_format
+ * parameters are handy in case the date and time values
+ * come from different fields.
+ *
+ * @param string $param The name of the date/time field.
+ * @param string $format The date format of the date/time field.
+ * @param string $second_param The name of the second field, if used.
+ * This parameter is optional.
+ * @param string $second_format The time format of the second field, if used.
+ * This parameter is optional.
+ * @param DateTime|null $default Either a default DateTime object
+ * or null if no default shall be set. In the latter case a DateTime
+ * object representing the unix timestamp 0 is returned.
+ *
+ * @returns DateTime|bool A DateTime object containing the
+ * date and time values of the specified date and time field.
+ * In case something went wrong the boolean value false is returned.
+ *
+ * @see the following PHP documentation page for a list of
+ * accepted date and time formats:
+ * https://secure.php.net/manual/en/datetime.createfromformat.php
+ */
+ public static function getDateTime(
+ $param = 'date',
+ $format = 'Y-m-d',
+ $second_param = null,
+ $second_format = null,
+ $default = null
+ )
+ {
+ $value = self::get($param);
+
+ if (!$value) {
+ //In case the first field is not set
+ //use the default value, if any:
+ if ($default instanceof DateTime) {
+ return $default;
+ } else {
+ $datetime = new DateTime();
+ $datetime->setTimestamp(0);
+ return $datetime;
+ }
+ }
+
+ //Combine the format specifications and the
+ //values into one string each.
+ $combined_format = $format;
+ $combined_value = $value;
+
+ //The second format and value is only added
+ //when $second_param and $second_format are set
+ //and a second value could be retrieved.
+ if ($second_param && $second_format) {
+ $second_value = Request::get($second_param);
+ if ($second_value) {
+ $combined_format .= ' ' . $second_format;
+ $combined_value .= ' ' . $second_value;
+ }
+ }
+
+ //The time zone may not be set in the fields
+ //so we use the default timezone from a new
+ //DateTime object:
+ $value = new DateTime();
+ $time_zone = $value->getTimezone();
+
+ //Now we return a DateTime object created from the
+ //specified date value(s):
+ $result = DateTime::createFromFormat(
+ $combined_format,
+ $combined_value,
+ $time_zone
+ );
+
+ if (
+ $result
+ && !$second_param
+ && !$second_format
+ && !preg_match('/[aAghGHisvu]/', $format) // Ensure no time in format
+ ) {
+ $result->setTime(0, 0);
+ }
+
+ return $result;
+ }
+
+
+ /**
+ * Retrieves a parameter that stores time data and converts the time data
+ * to a DateTime object. If a date is specified using an existing DateTime
+ * object, the time will be set on the existing DateTime object and the
+ * modified object is returned.
+ *
+ * @param string $param The name of the time field.
+ *
+ * @param string $format The time format of the time field.
+ *
+ * @param DateTime|null $date An optional DateTime object whose time
+ * shall be set from the specified parameter.
+ *
+ * @returns DateTime|bool A DateTime object containing the
+ * time value of the specified date and time field.
+ * In case something went wrong the boolean value false is returned.
+ *
+ */
+ public static function getTime(
+ $param = 'time',
+ $format = 'H:i',
+ $date = null
+ )
+ {
+ $value = Request::get($param);
+
+ //Get the timezone before parsing the time
+ //so that the resulting DateTime object
+ //will have the current timezone set.
+ $tz_get = new DateTime();
+ $time_zone = $tz_get->getTimezone();
+ $converted_value = DateTime::createFromFormat(
+ $format,
+ $value,
+ $time_zone
+ );
+
+ if ($date instanceof DateTime) {
+ //Modify the time information of the specified
+ //DateTime object and return the modified object.
+ $date->setTime(
+ intval($converted_value->format('H')),
+ intval($converted_value->format('i')),
+ intval($converted_value->format('s'))
+ );
+
+ return $date;
+ }
+
+ //Return the time value.
+ return $converted_value;
+ }
+
+
+ /**
+ * Return the value of the selected query parameter as a string
+ * consisting only of allowed characters for usernames.
+ *
+ * @param string $param parameter name
+ * @param string $default default value if parameter is not set
+ *
+ * @return string parameter value (if set), else NULL
+ */
+ public static function username($param, $default = NULL)
+ {
+ $value = self::get($param, $default);
+
+ if (!isset($value) || !preg_match(Config::get()->USERNAME_REGULAR_EXPRESSION, $value)) {
+ $value = $default;
+ }
+
+ return $value;
+ }
+
+ /**
+ * Return the value of the selected query parameter as an array.
+ *
+ * @param string $param parameter name
+ *
+ * @return array parameter value as array (if set), else an empty array
+ */
+ public static function getArray($param)
+ {
+ $request = self::getInstance();
+
+ return (isset($request[$param]) && is_array($request[$param]))
+ ? $request[$param]
+ : [];
+ }
+
+ /**
+ * Return the value of the selected query parameter as a string array.
+ * The contents of each element is quoted with addslashes().
+ *
+ * @param string $param parameter name
+ *
+ * @return array parameter value as array (if set), else an empty array
+ */
+ public static function quotedArray($param)
+ {
+ $array = self::getArray($param);
+
+ return self::addslashes($array);
+ }
+
+ /**
+ * Return the value of the selected query parameter as an array of
+ * alphanumeric strings (consisting of only digits, letters and
+ * underscores).
+ *
+ * @param string $param parameter name
+ *
+ * @return array parameter value as array (if set), else an empty array
+ */
+ public static function optionArray($param)
+ {
+ $array = self::getArray($param);
+
+ foreach ($array as $key => $value) {
+ if (preg_match('/\\W/', $value)) {
+ unset($array[$key]);
+ }
+ }
+
+ return $array;
+ }
+
+ /**
+ * Return the value of the selected query parameter as an integer array.
+ *
+ * @param string $param parameter name
+ *
+ * @return array parameter value as array (if set), else an empty array
+ */
+ public static function intArray($param)
+ {
+ $array = self::getArray($param);
+
+ foreach ($array as $key => $value) {
+ $array[$key] = (int) $value;
+ }
+
+ return $array;
+ }
+
+ /**
+ * Return the value of the selected query parameter as a float array.
+ *
+ * @param string $param parameter name
+ *
+ * @return array parameter value as array (if set), else an empty array
+ */
+ public static function floatArray($param)
+ {
+ $array = self::getArray($param);
+
+ foreach ($array as $key => $value) {
+ $array[$key] = (float) strtr($value, ',', '.');
+ }
+
+ return $array;
+ }
+
+ /**
+ * Return the value of the selected query parameter as a boolean.
+ *
+ * @param string $param parameter name
+ * @param bool $default default value if parameter is not set
+ *
+ * @return bool parameter value as bool (if set), else NULL
+ *
+ * @since Stud.IP 4.4
+ */
+ public static function bool($param, $default = null)
+ {
+ $value = self::get($param, $default);
+
+ if (isset($value)) {
+ $value = (bool) $value;
+ }
+
+ return $value;
+ }
+
+ /**
+ * Return the value of the selected query parameter as a boolean array.
+ *
+ * @param string $param parameter name
+ *
+ * @return array parameter value as array (if set), else an empty array
+ *
+ * @since Stud.IP 4.4
+ */
+ public static function boolArray($param)
+ {
+ $array = self::getArray($param);
+
+ foreach ($array as $key => $value) {
+ $array[$key] = (bool) $value;
+ }
+
+ return $array;
+ }
+
+ /**
+ * Return the value of the selected query parameter as an array of
+ * strings consisting only of allowed characters for usernames.
+ *
+ * @param string $param parameter name
+ *
+ * @return array parameter value as array (if set), else an empty array
+ */
+ public static function usernameArray($param)
+ {
+ $array = self::getArray($param);
+
+ foreach ($array as $key => $value) {
+ if (!preg_match(Config::get()->USERNAME_REGULAR_EXPRESSION, $value)) {
+ unset($array[$key]);
+ }
+ }
+
+ return $array;
+ }
+ /**
+ * Check whether a form submit button has been pressed. This works for
+ * both image and text submit buttons.
+ *
+ * @param string $param submit button name
+ *
+ * @returns boolean true if the button has been submitted, else false
+ */
+ public static function submitted($param)
+ {
+ $request = self::getInstance();
+
+ return isset($request[$param])
+ || isset($request[$param . '_x']);
+ }
+
+ /**
+ * Check whether one of the form submit buttons has been
+ * pressed. This works for both image and text submit buttons.
+ *
+ * @param string ...
+ * a variable argument list of submit button names
+ *
+ * @returns boolean true if any button has been submitted, else false
+ */
+ public static function submittedSome($param/*, ... */)
+ {
+ foreach(func_get_args() as $button) {
+ if (self::submitted($button)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ /**
+ * Quote a given string or array using addslashes(). If the parameter
+ * is an array, the quoting is applied recursively.
+ *
+ * @param mixed $value string or array value to be quoted
+ *
+ * @return mixed quoted string or array
+ */
+ public static function addslashes($value)
+ {
+ if (is_array($value)) {
+ foreach ($value as $key => $val) {
+ $value[$key] = self::addslashes($val);
+ }
+ } else {
+ $value = addslashes($value);
+ }
+
+ return $value;
+ }
+
+ /**
+ * Returns the (uppercase) request method.
+ *
+ * @return string the uppercased method of the request
+ */
+ public static function method()
+ {
+ return mb_strtoupper($_SERVER['X_HTTP_METHOD_OVERRIDE'] ?? $_SERVER['REQUEST_METHOD']);
+ }
+
+ /**
+ * @return boolean true if this a GET request
+ */
+ public static function isGet()
+ {
+ return self::method() === 'GET';
+ }
+
+ /**
+ * @return boolean true if this a POST request
+ */
+ public static function isPost()
+ {
+ return self::method() === 'POST';
+ }
+
+ /**
+ * @return boolean true if this a PUT request
+ */
+ public static function isPut()
+ {
+ return self::method() === 'PUT';
+ }
+
+ /**
+ * @return boolean true if this a DELETE request
+ */
+ public static function isDelete()
+ {
+ return self::method() === 'DELETE';
+ }
+
+
+ /**
+ * @return boolean true if this an XmlHttpRequest sent by jQuery/prototype
+ */
+ public static function isXhr()
+ {
+ return isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
+ strcasecmp($_SERVER['HTTP_X_REQUESTED_WITH'], 'xmlhttprequest') === 0;
+ }
+
+ /**
+ * This is an alias of Request::isXhr
+ *
+ * @return boolean true if this an XmlHttpRequest sent by jQuery/prototype
+ */
+ public static function isAjax()
+ {
+ return self::isXhr();
+ }
+
+ /**
+ * extracts some params from request, the desired params must be a comma separated list
+ * for each param, the type of used extraction method can be specified after the name,
+ * default is get
+ * null values are not returned
+ *
+ * e.g.:
+ * $data = Request::extract('admission_prelim int, admission_binding submitted, admission_prelim_txt');
+ * will yield
+ * array(3) {
+ * ["admission_prelim"]=>
+ * int(1)
+ * ["admission_binding"]=>
+ * bool(false)
+ * ["admission_prelim_txt"]=>
+ * string(0) ""
+ * }
+ * @param string $what comma separated list of param names and types
+ * @return array assoc array with extracted data
+ */
+ public static function extract($what)
+ {
+ $extract = [];
+ $return = [];
+ foreach (explode(',', $what) as $one) {
+ $extract[] = array_values(array_filter(array_map('trim', explode(' ', $one))));
+ }
+ foreach ($extract as $one) {
+ [$param, $func] = $one;
+ if (!$func) {
+ $func = 'get';
+ }
+ $value = self::$func($param);
+ if ($value !== null) {
+ $return[$param] = $value;
+ }
+ }
+ return $return;
+ }
+
+ /**
+ * returns true if http header indicates that the response will be rendered as dialog
+ *
+ * @return bool
+ */
+ public static function isDialog()
+ {
+ return self::isXhr() && isset($_SERVER['HTTP_X_DIALOG']);
+ }
+
+ /**
+ * Returns an object that has previously been serialized using the
+ * ObjectBuilder.
+ *
+ * @param String $param parameter name
+ * @param mixed $expected_class Expected class name of object (optional)
+ * @param bool $allow_null If true, return null on error; otherwise an
+ * exception is thrown
+ * @return mixed Object of arbitrary type or null on error and $allow_null
+ * @throws Exception when an error occurs and $allow_null = false
+ * @see ObjectBuilder
+ */
+ public static function getObject($param, $expected_class = null, $allow_null = true)
+ {
+ try {
+ return ObjectBuilder::build(Request::get($param), $expected_class);
+ } catch (Exception $e) {
+ if ($allow_null) {
+ return null;
+ }
+
+ throw $e;
+ }
+ }
+
+ /**
+ * Returns a collection of objects that have previously been serialized
+ * using the ObjectBuilder.
+ *
+ * @param String $param parameter name
+ * @param mixed $expected_class Expected class name of objects (optional)
+ * @param bool $allow_null If true, return empty array on error;
+ * otherwise an exception is thrown
+ * @return array as collection of objects
+ * @throws Exception when an error occurs and $allow_null = false
+ * @see ObjectBuilder
+ */
+ public static function getManyObjects($param, $expected_class = null, $allow_null = true)
+ {
+ try {
+ $request = self::getInstance();
+ return ObjectBuilder::buildMany($request[$param] ?? null, $expected_class);
+ } catch (Exception $e) {
+ if ($allow_null) {
+ return [];
+ }
+
+ throw $e;
+ }
+ }
+}