FRED™  3.0
FRED™: Framework for Rapid and Easy Development
Request.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Rsi\Fred;
4 
5 /**
6  * Component comprising all information regarding an HTTP-request (to transport these along all stepts executed during a
7  * request).
8  */
9 class Request extends Component{
10 
11  public $encoding = 'UTF-8'; //!< Check encoding.
12  public $errors = []; //!< Errors detected during the processing of the request (key = item ID, value = error code).
13  public $data = []; //!< Data to be presented by the view (key-value pairs).
14  public $result = null; //!< Result fo the request (mixed).
15  public $redir = null; //!< URL for redirection (empty = no redirection).
16  public $viewControllerName = null; //!< Name of the view controller (same as the request handler when empty).
17 
18  public $cookieOptions = []; //!< Default cookie options.
19  public $jsonDecodingError = 'JSON decoding error: [error]';
20  public $postExceededError = 'POST exceeded ([size] / [max])';
21 
22  protected $_files = null;
23  protected $_server = null;
24 
25  protected function init(){
26  parent::init();
27  if(\Rsi\Http::method() == 'POST') $this->checkPost();
28  }
29  /**
30  * Checks the post (by content type).
31  */
32  protected function checkPost(){
33  try{
34  switch($_SERVER['CONTENT_TYPE'] ?? null){
35  case 'application/json':
36  if(is_array($data = json_decode(file_get_contents('php://input'),true))) $_POST = $data;
37  if(json_last_error()) $this->component('trans')->str($this->jsonDecodingError,['error' => json_last_error_msg()]);
38  break;
39  case 'application/xml':
40  if(is_array($data = json_decode(json_encode(simplexml_load_file('php://input',null,LIBXML_NOCDATA)),true))) $_POST = $data;
41  break;
42  default:
43  if(\Rsi\Http::postExceeded($size,$max)){
44  $local = $this->component('local');
45  $this->errors['post'] = $this->component('trans')->str($this->postExceededError,['size' => $local->formatBytes($size),'max' => $local->formatBytes($max)]);
46  }
47  }
48  }
49  catch(\Exception $e){
50  $this->_fred->externalError($e->getMessage());
51  }
52  }
53  /**
54  * Transform an array of uploaded files to a 'normal' structure.
55  * Single file uploads have an entry in the $_FILES array with properties 'tmp_name', 'size', and so on. With an array of
56  * files this is also the case, and each of these property has a multi dimensional array of values. For the processing of
57  * single files though it is more convinient if all files have the same single dimension array structure as the single file
58  * upload at the deepest level. Therefore the property names must move to the end of the structure.
59  * @param array $values Array with properties (single or multi dimensional).
60  * @param array $prefix Array to prefix before the keys.
61  * @param array $files Already determined, correct structure.
62  * @return array Complemented, correct structure.
63  */
64  protected function fixFileKey($values,$prefix = null,$files = null){
65  if(!$prefix) $prefix = $files = [];
66  foreach($values as $key => $value){
67  $key = array_merge($prefix,[$key]);
68  if(is_array($value)) $files = $this->fixFileKey($value,$key,$files);
69  else{
70  $item = array_shift($key);
71  \Rsi\Record::set($files,array_merge($key,[$item]),$value);
72  }
73  }
74  return $files;
75  }
76  /**
77  * Map command line arguments to the $_GET.
78  * @param array $keys Array with key for every consecutive argument. If empty, the argument itself is parsed for keys
79  * ("key=value foo=bar" format).
80  */
81  public function mapArgs($keys = null){
82  global $argv;
83 
84  if($keys) foreach(array_values($keys) as $index => $key) $_GET[$key] = $argv[$index + 1] ?? null;
85  else parse_str(implode('&',array_slice($argv,1)),$_GET);
86  }
87  /**
88  * Retrieve a file upload from the request.
89  * @param string $key Name of the sought file.
90  * @return mixed Found value (might be empty or have errors).
91  */
92  public function file($key){
93  return \Rsi\Record::get($this->files,$key);
94  }
95  /**
96  * Retrieve a complex parameter (simple type or array) from the request.
97  * Parameters are first sought-after in the $_POST, then in the $_FILES, and last in the $_GET. Only the latter will be done
98  * case insensitive.
99  * @param string $key Name of the sought parameter.
100  * @param mixed $default Default value if the key does not exist.
101  * @return mixed Found value, or default value if the key does not exist.
102  */
103  public function complex($key,$default = null){
104  if(($value = \Rsi\Record::get($_POST,$key,false)) !== false) return $value;
105  if(($value = $this->file($key)) !== null) return $value;
106  return \Rsi\Record::iget($_GET,$key,$default);
107  }
108  /**
109  * Retrieve a record like parameter (single layer array) from the request.
110  * @see complex()
111  * @param string $key Name of the sought parameter.
112  * @param mixed $default Default value if the key does not exist.
113  * @return mixed Found value, or default value if the key does not exist or the value is not valid.
114  */
115  public function record($key,$default = null){
116  if(!is_array($value = $this->complex($key,$default))) return $default;
117  foreach($value as $sub) if(is_array($sub) || ($this->encoding && !mb_check_encoding($sub,$this->encoding))) return $default;
118  return $value;
119  }
120  /**
121  * Retrieve a simple parameter (not an array) from the request.
122  * @see complex()
123  * @param string $key Name of the sought parameter.
124  * @param mixed $default Default value if the key does not exist.
125  * @param string $mask Regex to check the value with (true = word chars only).
126  * @return mixed Found value, or default value if the key does not exist or the value is not valid.
127  */
128  public function simple($key,$default = null,$mask = null){
129  return (
130  is_array($value = $this->complex($key,$default)) ||
131  ($this->encoding && !mb_check_encoding($value,$this->encoding)) ||
132  ($mask && !preg_match($mask === true ? '/^\\w+$/' : $mask,$value))
133  ) ? $default : $value;
134  }
135 
136  public function data($key,$default = null){
137  return \Rsi\Record::get($this->data,$key,$default);
138  }
139  /**
140  * Set and/or get a cookie.
141  * @param string $key Cookie key.
142  * @param mixed $value Cookie value.
143  * @param int $days Cookie lifetime (in days).
144  * @param array $options Cookie options (see https://www.php.net/setcookie; when 'secure' is undefined, the value is
145  * automaticly set to true when the request was made using a secure connection).
146  * @return mixed Cookie value (false when unknown).
147  */
148  public function cookie($key,$value = null,$days = 365,$options = null){
149  if(func_num_args() > 1) \Rsi\Http::setCookie($key,$value,$days,($options ?: []) + $this->cookieOptions);
150  return $_COOKIE[$key] ?? false;
151  }
152 
153  protected function getFiles(){
154  if($this->_files === null){
155  $this->_files = [];
156  foreach($_FILES as $key => $value) $this->_files[$key] = $this->fixFileKey($value);
157  }
158  return $this->_files;
159  }
160 
161  protected function getServer(){
162  if($this->_server === null){
163  $server = ['http' => []];
164  foreach($_SERVER as $key => $value)
165  if(substr($key = strtolower($key),0,5) == 'http_') $server['http'][lcfirst(\Rsi\Str::camel(substr($key,5)))] = $value;
166  else $server[lcfirst(\Rsi\Str::camel($key))] = $value;
167  $this->_server = new \Rsi\Wrapper\Record($server);
168  }
169  return $this->_server;
170  }
171 
172  protected function _get($key){
173  return array_key_exists($key,$this->data) ? $this->data[$key] : $this->simple($key);
174  }
175 
176  protected function _set($key,$value){
177  $this->data[$key] = $value;
178  }
179 
180  public function __invoke($key,$default = null){
181  return $this->data($key,$default);
182  }
183 
184 }
$errors
Errors detected during the processing of the request (key = item ID, value = error code)...
Definition: Request.php:12
$redir
URL for redirection (empty = no redirection).
Definition: Request.php:15
mapArgs($keys=null)
Map command line arguments to the $_GET.
Definition: Request.php:81
checkPost()
Checks the post (by content type).
Definition: Request.php:32
__invoke($key, $default=null)
Definition: Request.php:180
record($key, $default=null)
Retrieve a record like parameter (single layer array) from the request.
Definition: Request.php:115
data($key, $default=null)
Definition: Request.php:136
fixFileKey($values, $prefix=null, $files=null)
Transform an array of uploaded files to a &#39;normal&#39; structure.
Definition: Request.php:64
_set($key, $value)
Definition: Request.php:176
file($key)
Retrieve a file upload from the request.
Definition: Request.php:92
$cookieOptions
Default cookie options.
Definition: Request.php:18
$viewControllerName
Name of the view controller (same as the request handler when empty).
Definition: Request.php:16
$result
Result fo the request (mixed).
Definition: Request.php:14
Basic component class.
Definition: Component.php:8
cookie($key, $value=null, $days=365, $options=null)
Set and/or get a cookie.
Definition: Request.php:148
complex($key, $default=null)
Retrieve a complex parameter (simple type or array) from the request.
Definition: Request.php:103
$data
Data to be presented by the view (key-value pairs).
Definition: Request.php:13
$encoding
Check encoding.
Definition: Request.php:11
Component comprising all information regarding an HTTP-request (to transport these along all stepts e...
Definition: Request.php:9
component($name)
Get a component (local or default).
Definition: Component.php:80
simple($key, $default=null, $mask=null)
Retrieve a simple parameter (not an array) from the request.
Definition: Request.php:128