Skip to content
Snippets Groups Projects
Select Git revision
  • 60c69f2ab1e5a81eb2196821e5aa932df8e5f6cf
  • main default protected
  • 5.5 protected
  • atlantis
  • 5.3 protected
  • 5.0 protected
  • issue-23
  • issue8-seat-logging-and-export
  • ticket-216
  • tickets-215-216-241-242
10 results

Course.php

Blame
  • Forked from Stud.IP / Stud.IP
    Source project has a limited visibility.
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    Request.php 21.71 KiB
    <?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 I18NString|string|null $default default value if parameter is not set
         * @param callable|null          $op      Operation to perform on each text string
         *
         * @return I18NString  parameter value as string (if set), else NULL
         */
        public static function i18n(string $param, $default = null, Callable $op = null)
        {
            $value = self::get($param, $default instanceof I18NString ? $default->original() : $default);
    
            if (isset($value)) {
                $lang = self::getArray($param . '_i18n') ?: ($default instanceof I18NString ? $default->toArray() : []);
    
                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 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) {
                // 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 !== false) {
                    if (
                        !$second_param
                        && !$second_format
                        && !preg_match('/[aAghGHisvu]/', $format) // Ensure no time in format
                    ) {
                        $result->setTime(0, 0);
                    }
    
                    return $result;
                }
            }
    
    
            // In case the first field is not set
            // use the default value, if any:
            if ($default instanceof DateTime) {
                return $default;
            }
    
            return false;
        }
    
    
        /**
         * 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 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;
        }
    
        /**
         * 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 = $one[0];
                $func = $one[1] ?? '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;
            }
        }
    }