File modules/cms/action/RequestParams.class.php

Last commit: Tue Oct 13 22:52:59 2026 +0200	Jan Dankert	New: The UI is now able to send hierarchical form data and the server is converting it into an object. This is a very nice feature, because this enables a better OpenAPI interface.
1 <?php 2 3 namespace cms\action; 4 5 use cms\api\Values; 6 use util\exception\ValidationException; 7 use util\Hydrator; 8 use util\json\JSON; 9 use util\mail\Mail; 10 use util\Text; 11 use util\YAML; 12 13 14 class RequestParams 15 { 16 const PARAM_TOKEN = 'token' ; 17 const PARAM_ACTION = 'action' ; 18 const PARAM_SUBACTION = 'subaction' ; 19 const PARAM_ID = 'id' ; 20 const PARAM_LANGUAGE_ID = 'languageid' ; 21 const PARAM_MODEL_ID = 'modelid' ; 22 const PARAM_PROJECT_ID = 'projectid' ; 23 const PARAM_DATABASE_ID = 'dbid' ; 24 const PARAM_OUTPUT = 'output' ; 25 26 public $action; 27 public $method; 28 public $id; 29 30 public $isAction; 31 32 /** 33 * Request headers. 34 * @var array 35 */ 36 37 public $headers; 38 public $authUser; 39 public $authPassword; 40 public $authToken; 41 public $apiToken; 42 43 private array $parameter; 44 45 /** 46 * @var bool 47 */ 48 public $isUIAction; 49 50 51 /** 52 * @var bool 53 */ 54 public $withAuthorization; 55 56 /** 57 * RequestParams constructor. 58 */ 59 public function __construct() 60 { 61 // Is this a POST request? 62 $this->isAction = @$_SERVER['REQUEST_METHOD'] == 'POST'; 63 $this->headers = array_change_key_case(getallheaders(), CASE_LOWER); 64 65 $this->tryBasicAuthorization(); 66 67 $this->setParameterStore(); 68 69 if ( defined("API_CALL") ) { 70 $this->id = API_ID; 71 $this->action = API_ACTION; 72 $this->method = API_SUBACTION; 73 } else { 74 $this->id = $this->getAlphanum(self::PARAM_ID ); 75 $this->action = $this->getAlphanum(self::PARAM_ACTION ); 76 $this->method = $this->getAlphanum(self::PARAM_SUBACTION); 77 } 78 } 79 80 81 /** 82 * Setting the source for request parameters. 83 */ 84 protected function setParameterStore() { 85 86 87 $contenttype = trim(explode( ';',@$this->headers['content-type'])[0]); 88 89 if ( !$this->isAction ) 90 $this->parameter = &$_GET; 91 // GET method in the HTTP/1.1 spec, section 9.3: 92 // The GET method means retrieve whatever information ([...]) is identified by the Request-URI. 93 // so the request body MUST be ignored here. 94 else 95 // POST requests are NOT idempotent 96 switch( $contenttype ) { 97 // These content-types are known by PHP, so we do NOT have to parse them: 98 case 'application/x-www-form-urlencoded': // the most used form url encoding 99 case 'multipart/form-data': // Multipart-Formdata for File uploads 100 case '': 101 $this->parameter = &$_POST; // Using builtin POST data parsing 102 break; 103 104 // The request body contains a JSON document 105 case 'text/json': 106 case 'application/json': 107 // parsing the JSON data 108 $this->parameter = JSON::decode(file_get_contents("php://input")); 109 break; 110 111 case 'text/xml': 112 case 'application/xml': 113 $this->parameter = (array)simplexml_load_string(file_get_contents("php://input")); 114 break; 115 116 case 'application/yaml': 117 $this->parameter = YAML::parse(file_get_contents("php://input")); 118 break; 119 120 default: 121 // Unknown content type 122 throw new \LogicException('HTTP-POST with unknown content type: ' . $contenttype); 123 } 124 125 } 126 127 128 129 /** 130 * Ermittelt den Inhalt der gew�nschten Request-Variablen. 131 * Falls nicht vorhanden, wird "" zur�ckgegeben. 132 * 133 * @param String $varName Schl�ssel 134 * @return String Inhalt 135 */ 136 protected function getValue($varName) 137 { 138 if ( ! $this->hasKey($varName) ) 139 return null; 140 141 return $this->parameter[$varName]; 142 } 143 144 protected function requireVar( $varName ) 145 { 146 if ( ! $this->hasKey($varName) ) 147 throw new ValidationException( $varName ); 148 149 return; 150 } 151 152 153 public function getAlphanum($varName ) { 154 return Text::clean( $this->getValue($varName), 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.,_-!?%&/()' ); 155 } 156 157 158 public function getFilename($varName ) { 159 160 // RFC 1738, Section 2.2: 161 // Thus, only alphanumerics, the special characters "$-_.+!*'(),", and 162 // reserved characters used for their reserved purposes may be used 163 // unencoded within a URL. 164 return Text::clean( $this->getValue($varName), 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$-_.+!*(),\'' ); 165 } 166 167 168 /** 169 * Gets a mail adress out of the request. 170 * 171 * Throws a ValidationException if the mail adress is not valid. 172 * 173 * @param $varName 174 * @return String 175 */ 176 public function getValidMail($varName ) { 177 178 $adress = Text::clean( $this->getValue($varName), 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-+@' ); 179 180 if ( ! Mail::checkAddress( $adress ) ) 181 throw new ValidationException( $varName ); 182 183 return $adress; 184 } 185 186 187 public function getRaw($varName ) { 188 return $this->getValue( $varName ); 189 } 190 191 192 /** 193 * Get required parameter value. 194 * 195 * @param $varName 196 * @return String|null 197 * @throws ValidationException 198 */ 199 public function getRequiredRaw($varName ) { 200 201 $this->requireVar( $varName ); 202 203 return $this->getValue( $varName ); 204 } 205 206 207 /** 208 * @param $varName 209 * @return string|null 210 */ 211 public function getText( $varName ) { 212 213 if ( ! $this->hasKey($varName )) 214 return null; 215 216 // Allow all UTF-8 characters. 217 return mb_convert_encoding($this->getValue($varName), 'UTF-8', 'UTF-8'); 218 } 219 220 221 /** 222 * @param $varName string name of request parameter 223 * @param $callback callable only called if the request parameter is given by the client 224 */ 225 public function handleText( $varName,$callback ) { 226 227 if ( $this->hasKey($varName ) ) 228 call_user_func( $callback, $this->getText($varName) ); 229 } 230 231 /** 232 * @param $varName 233 * @param $callback 234 */ 235 public function handleNumber( $varName,$callback ) { 236 237 if ( $this->hasKey($varName ) ) 238 call_user_func( $callback, $this->getNumber($varName) ); 239 } 240 241 /** 242 * @param $varName 243 * @param $callback 244 */ 245 public function handleBool($varName, $callback ) { 246 247 call_user_func( $callback, $this->isTrue($varName) ); 248 } 249 250 251 /** 252 * Gets the value of the request parameter. 253 * 254 * @param $nameOfRequestParameter 255 * @return String 256 * @throws ValidationException 257 */ 258 public function getRequiredText( $nameOfRequestParameter ) { 259 260 $this->requireVar( $nameOfRequestParameter ); 261 262 return $this->getText( $nameOfRequestParameter ); 263 } 264 265 266 267 /** 268 * Gets the value of the request parameter. 269 * 270 * @param $nameOfRequestParameter 271 * @return String 272 * @throws ValidationException 273 */ 274 public function getNotEmptyText( $nameOfRequestParameter ) { 275 276 if ( $value = $this->getRequiredText( $nameOfRequestParameter ) ) 277 return $value; 278 else 279 return new ValidationException( $nameOfRequestParameter ); 280 } 281 282 283 284 /** 285 * Checks if the request contains the parameter. 286 * 287 * @param String $varName Schl�ssel 288 * @return boolean true, falls vorhanden. 289 */ 290 protected function hasKey($varName) 291 { 292 return isset( $this->parameter[$varName] ); 293 } 294 295 296 /** 297 * Gets the ID for the current action. 298 * 299 * @return Integer 300 */ 301 public function getId() 302 { 303 return $this->id; 304 } 305 306 307 /** 308 * Ermittelt die aktuelle Id aus dem Request.<br> 309 * Um welche ID es sich handelt, ist abh�ngig von der Action. 310 * 311 * @param string $varName name of parameter 312 * @return Integer 313 */ 314 public function getNumber( $varName ) 315 { 316 if ( ! $this->hasKey($varName )) 317 return null; 318 319 return intval($this->getValue( $varName )); 320 } 321 322 323 324 325 /** 326 * Ermittelt einen Float-Wert aus dem Request.<br> 327 * 328 * @param string $varName name of parameter 329 * @return Float 330 */ 331 public function getFloat( $varName ) 332 { 333 if ( ! $this->hasKey($varName )) 334 return null; 335 336 return floatval($this->getValue( $varName )); 337 } 338 /** 339 * Checks if the parameter value is true. 340 * 341 * @param string $varName name of parameter 342 * @return Integer 343 */ 344 public function isTrue( $varName ) 345 { 346 return in_array( $this->getValue($varName),['1','true','on']); 347 } 348 349 350 351 352 /** 353 * Ermittelt die aktuelle Id aus dem Request.<br> 354 * Um welche ID es sich handelt, ist abh�ngig von der Action. 355 * 356 * @param string $varName name of parameter 357 * @return Integer 358 */ 359 public function getRequiredNumber($varName ) 360 { 361 $this->requireVar( $varName ); 362 363 return $this->getNumber( $varName ); 364 } 365 366 367 public function getLanguageId() 368 { 369 return $this->getNumber(self::PARAM_LANGUAGE_ID); 370 } 371 372 373 public function getModelId() 374 { 375 return $this->getNumber(self::PARAM_MODEL_ID ); 376 } 377 378 379 public function getProjectId() 380 { 381 return $this->getNumber(self::PARAM_PROJECT_ID ); 382 } 383 384 385 public function getDatabaseId() 386 { 387 return $this->getAlphanum(self::PARAM_DATABASE_ID ); 388 } 389 390 391 public function getToken() 392 { 393 return $this->getAlphanum(self::PARAM_TOKEN ); 394 } 395 396 397 public function __toString() { 398 return 'Request '.$this->action.'/'.$this->method.'/'.$this->id; 399 } 400 401 402 /** 403 * Redirect to a new action and method. 404 * 405 * @param $action 406 * @param $method 407 */ 408 public function redirectActionAndMethod( $action, $method ) { 409 410 $this->action = $action; 411 $this->method = $method; 412 } 413 414 415 /** 416 * Basic Authorization. 417 * 418 * Try login with basic authorization. This is useful for API clients, they to not need to track a session with cookies. 419 */ 420 private function tryBasicAuthorization() 421 { 422 if ( $auth = @$this->headers['authorization'] ) { 423 424 $this->withAuthorization = true; 425 list( $type,$value ) = array_pad( explode(' ',$auth),2,''); 426 switch( $type ) { 427 case 'Basic': 428 list($this->authUser,$this->authPassword) = array_pad(explode(':',base64_decode( $value )),2,'' ); 429 break; 430 case 'API': 431 case 'CMS-API': 432 $this->apiToken = $value; 433 case 'Bearer': 434 case 'JWT': 435 $this->authToken = $value; 436 break; 437 default: 438 // Only supporting Basic Auth and Bearer Auth 439 error_log('Only supporting the authorization schemes Basic, Bearer and API. Authorization header will be ignored.'); 440 } 441 442 } 443 } 444 445 446 public function getRawParameters(): array 447 { 448 return $this->parameter; 449 } 450 451 public function toObject(string $class): object 452 { 453 return Hydrator::map( $class,$this->getRawParameters() ); 454 } 455 }
Download modules/cms/action/RequestParams.class.php
History Tue, 13 Oct 2026 22:52:59 +0200 Jan Dankert New: The UI is now able to send hierarchical form data and the server is converting it into an object. This is a very nice feature, because this enables a better OpenAPI interface. Wed, 4 Jun 2025 22:33:49 +0200 Jan Dankert Fix: Getting the Request-Id was completly broken for whole UI :-O Thu, 24 Apr 2025 00:13:35 +0200 Jan Dankert New: OpenAPI with REST interface for all actions and methods Mon, 6 Jan 2025 22:48:11 +0100 Jan Dankert New: Now it is possible to remove and create new login/api token for a user; new API authorization with the authorization scheme "api". Mon, 22 Apr 2024 22:29:49 +0200 Jan Dankert Editing coordinates now possible. Thu, 28 Apr 2022 00:28:24 +0200 Jan Dankert New: Login with Json webtoken (JWT) Mon, 25 Apr 2022 03:26:21 +0200 Jan Dankert New: New Project may be created with sample data. Fri, 15 Apr 2022 14:51:22 +0200 dankert Refactoring: User,Config and Database info is now stored in the Request, because so there is no session required for clients which are using Basic Authorization. Wed, 9 Mar 2022 13:28:52 +0100 dankert Refactoring: Checkbox values are always sent to the server. In the actions we must test the value with 'isTrue()' Wed, 9 Mar 2022 00:52:23 +0100 dankert New: Only save a property if it is send by the client. This is useful using a API, so not sent properties will not be deleted. Sun, 13 Feb 2022 19:39:49 +0100 dankert Refactoring: Special output type "preview" for previewing pages and files. Mon, 7 Feb 2022 21:44:42 +0100 dankert New: Authenticate API users with the HTTP authorization header. Mon, 7 Feb 2022 19:48:06 +0100 dankert New: Support for YAML in request body. Wed, 17 Nov 2021 23:29:17 +0100 Jan Dankert Refactoring: New method for redirecting action and method. Wed, 27 Oct 2021 02:27:59 +0200 Jan Dankert Refactoring: Splitted the mail client into a.) sendmail and b.) smtp. Thu, 11 Mar 2021 00:01:47 +0100 Jan Dankert Refactoring: Cleaned the Request params. Wed, 10 Mar 2021 23:51:22 +0100 Jan Dankert Refactoring: Cleaned the Request params. Sat, 27 Feb 2021 01:07:14 +0100 Jan Dankert Fix: Request-Id may contain '_'. Fri, 26 Feb 2021 01:06:01 +0100 Jan Dankert Refactoring accessing the request parameter values. Fri, 26 Feb 2021 00:04:49 +0100 Jan Dankert New: Request may contain JSON,XML in POST data. This is good for API clients. Thu, 25 Feb 2021 01:22:10 +0100 Jan Dankert New: Edit all page elements in 1 view. Sat, 20 Feb 2021 00:49:37 +0100 Jan Dankert Cleanup of templates. Sat, 31 Oct 2020 01:19:06 +0100 Jan Dankert Better logging in the dispatcher. Tue, 29 Sep 2020 22:17:11 +0200 Jan Dankert Refactoring: Do not use global constants. Sat, 26 Sep 2020 21:42:51 +0200 Jan Dankert Refactoring: The UI Actions are now in their own namespace. No need for a confusing require file. Sat, 26 Sep 2020 12:20:43 +0200 Jan Dankert Refactoring: No global variables like $SESS any more. All constants are capsulated by classes. Thu, 10 Sep 2020 18:30:16 +0200 Jan Dankert Some code cleanup, killing the old "checkMenu()"-methods. Thu, 10 Sep 2020 18:02:54 +0200 Jan Dankert The dispatcher is now able to call the action methods with parameters. Sun, 23 Feb 2020 04:01:30 +0100 Jan Dankert Refactoring with Namespaces for the cms modules, part 1: moving.