ILIAS  release_8 Revision v8.24
class.ilCtrl.php
Go to the documentation of this file.
1<?php
2
18declare(strict_types=1);
19
22use ILIAS\Refinery\Factory as Refinery;
25use Psr\Http\Message\ServerRequestInterface;
26use GuzzleHttp\Psr7\Response;
27
34class ilCtrl implements ilCtrlInterface
35{
41
46 private ServerRequestInterface $server_request;
47
53
59
64 private Refinery $refinery;
65
71
77
83
89
95
97
102 private array $stacktrace = [];
103
108 private ?object $exec_object = null;
109
123 public function __construct(
129 ServerRequestInterface $server_request,
132 Refinery $refinery,
135 ) {
136 $this->structure = $structure;
137 $this->token_repository = $token_repository;
138 $this->response_sender = $response_sender;
139 $this->server_request = $server_request;
140 $this->post_parameters = $post_parameters;
141 $this->get_parameters = $get_parameters;
142 $this->refinery = $refinery;
143 $this->path_factory = $path_factory;
144 $this->context = $context;
145 $this->component_factory = $component_factory;
146 $this->query_parser = $query_parser;
147 }
148
149 public function __clone()
150 {
151 $this->structure = clone $this->structure;
152 }
153
157 public function callBaseClass(string $a_base_class = null): void
158 {
159 // prioritise the context's baseclass over the given one.
160 $a_base_class = $this->context->getBaseClass() ?? $a_base_class;
161
162 // abort if no baseclass was provided.
163 if (null === $a_base_class) {
164 throw new ilCtrlException(__METHOD__ . " was not given a baseclass and the request doesn't include one either.");
165 }
166
167 // abort if the provided baseclass is unknown.
168 if (!$this->structure->isBaseClass($a_base_class)) {
169 throw new ilCtrlException("Provided class '$a_base_class' is not a baseclass");
170 }
171
172 // in case the baseclass was given by argument,
173 // set the context's baseclass.
174 $this->context->setBaseClass($a_base_class);
175
176 // no null-check needed as previous isBaseClass() was true.
177 $obj_name = $this->structure->getObjNameByName($a_base_class);
178 $this->forwardCommand(new $obj_name());
179 }
180
184 public function forwardCommand(object $a_gui_object)
185 {
186 $class_name = get_class($a_gui_object);
187
188 // @TODO: remove this check once an interface for command classes exists.
189 if (!method_exists($a_gui_object, 'executeCommand')) {
190 throw new ilCtrlException("$class_name doesn't implement executeCommand().");
191 }
192
193 $this->exec_object = $a_gui_object;
194 $this->populateCall($class_name, self::CMD_MODE_PROCESS);
195
196 // with forward command we cannot progress, or set
197 // the current command class. Otherwise, the path-
198 // finding gets mixed up, as it can only be used in
199 // getHTML() method calls.
200 $this->context
201 ->setCmdMode(self::CMD_MODE_PROCESS);
202
203 return $a_gui_object->executeCommand();
204 }
205
209 public function getHTML(object $a_gui_object, array $a_parameters = null): string
210 {
211 $class_name = get_class($a_gui_object);
212 // @TODO: remove this check once an interface for command classes exists.
213 if (!method_exists($a_gui_object, 'getHTML')) {
214 throw new ilCtrlException("$class_name doesn't implement getHTML().");
215 }
216
217 $isolatad_structure = $this->structure;
218 $isolated_context = $this->context;
219 $isolated_object = $this->exec_object;
220
221 $this->exec_object = $a_gui_object;
222 $this->populateCall($class_name, self::CMD_MODE_HTML);
223 $this->context
224 ->setCmdClass($class_name)
225 ->setCmdMode(self::CMD_MODE_HTML);
226
227 $html = (null !== $a_parameters) ?
228 $a_gui_object->getHTML($a_parameters) :
229 $a_gui_object->getHTML();
230
231 $this->structure = $isolatad_structure;
232 $this->context = $isolated_context;
233 $this->exec_object = $isolated_object;
234
235 return $html;
236 }
237
241 public function getCmd(string $fallback_command = null): ?string
242 {
243 // retrieve $_GET and $_POST parameters.
244 $post_command = $this->getPostCommand();
245 $get_command = $this->getQueryParam(self::PARAM_CMD);
246 $table_command = $this->getTableCommand();
247
248 $is_post = (self::CMD_POST === $get_command);
249
250 // if the $_GET command is 'post', either the $_POST
251 // command or $_GETs fallback command is used.
252 // for now, the table command is used as fallback as well,
253 // but this will be removed once the implementation of
254 // table actions change.
255 $command = ($is_post) ?
256 $post_command ?? $table_command ?? $this->getQueryParam(self::PARAM_CMD_FALLBACK) :
257 $get_command;
258
259 // override the command that has been set during a
260 // request via ilCtrl::setCmd().
261 $context_command = $this->context->getCmd();
262 if (null !== $context_command && self::CMD_POST !== $context_command) {
263 $command = $context_command;
264 }
265
266 if (null !== $command) {
267 // if the command is for post requests, or the command
268 // is not considered safe, the csrf-validation must pass.
269 $cmd_class = $this->context->getCmdClass();
270
271 if (null !== $cmd_class && !$this->isCmdSecure($is_post, $cmd_class, $command)) {
272 $stored_token = $this->token_repository->getToken();
273 $sent_token = $this->getQueryParam(self::PARAM_CSRF_TOKEN);
274
275 if (null !== $sent_token && $stored_token->verifyWith($sent_token)) {
276 return $command;
277 }
278 return $fallback_command ?? '';
279 }
280 return $command;
281 }
282
283 return $fallback_command ?? '';
284 }
285
289 public function setCmd(?string $a_cmd): void
290 {
291 if (!empty($a_cmd)) {
292 $this->context->setCmd($a_cmd);
293 } else {
294 $this->context->setCmd(null);
295 }
296 }
297
301 public function getCmdClass(): ?string
302 {
303 if (null !== ($cmd_class = $this->context->getCmdClass())) {
304 return strtolower($this->structure->getObjNameByName($cmd_class));
305 }
306
307 return '';
308 }
309
313 public function setCmdClass($a_cmd_class): void
314 {
315 if (!empty($a_cmd_class)) {
316 $this->context->setCmdClass($a_cmd_class);
317 } else {
318 $this->context->setCmdClass(null);
319 }
320 }
321
325 public function getNextClass($a_gui_class = null): ?string
326 {
327 if (null === $a_gui_class && null === $this->exec_object) {
328 return '';
329 }
330
331 if (null === $this->context->getPath()) {
332 return '';
333 }
334
335 $next_cid = $this->context->getPath()->getNextCid(
336 $this->getClassByObject($a_gui_class ?? $this->exec_object)
337 );
338
339 if (null !== $next_cid) {
340 return strtolower($this->structure->getObjNameByCid($next_cid) ?? '');
341 }
342
343 return '';
344 }
345
349 public function saveParameter(object $a_gui_obj, $a_parameter): void
350 {
351 $this->saveParameterByClass($this->getClassByObject($a_gui_obj), $a_parameter);
352 }
353
357 public function saveParameterByClass(string $a_class, $a_parameter): void
358 {
359 if (!empty($a_parameter)) {
360 if (is_array($a_parameter)) {
361 foreach ($a_parameter as $parameter) {
362 $this->structure->setPermanentParameterByClass($a_class, $parameter);
363 }
364 } else {
365 $this->structure->setPermanentParameterByClass($a_class, $a_parameter);
366 }
367 }
368 }
369
373 public function setParameter(object $a_gui_obj, string $a_parameter, $a_value): void
374 {
375 $this->setParameterByClass($this->getClassByObject($a_gui_obj), $a_parameter, $a_value);
376 }
377
381 public function setParameterByClass(string $a_class, string $a_parameter, $a_value): void
382 {
383 $this->structure->setTemporaryParameterByClass($a_class, $a_parameter, $a_value);
384 }
385
389 public function getParameterArray(object $a_gui_obj): array
390 {
391 return $this->getParameterArrayByClass($this->getClassByObject($a_gui_obj));
392 }
393
397 public function getParameterArrayByClass(string $a_class): array
398 {
399 if (null === $this->structure->getClassCidByName($a_class)) {
400 throw new ilCtrlException("Cannot find provided class '$a_class' in the control structure.");
401 }
402
403 $parameters = [];
404 $permanent_parameters = $this->structure->getPermanentParametersByClass($a_class);
405 if (null !== $permanent_parameters) {
406 foreach ($permanent_parameters as $parameter) {
407 $parameters[$parameter] = $this->getQueryParam($parameter);
408 }
409 }
410
411 $temporary_parameters = $this->structure->getTemporaryParametersByClass($a_class);
412 if (null !== $temporary_parameters) {
413 // override existing ones, as temporary parameters
414 // are prioritised over fetched ones.
415 foreach ($temporary_parameters as $key => $value) {
416 $parameters[$key] = $value;
417 }
418 }
419
420 return $parameters;
421 }
422
426 public function clearParameters(object $a_gui_obj): void
427 {
428 $this->clearParametersByClass($this->getClassByObject($a_gui_obj));
429 }
430
434 public function clearParametersByClass(string $a_class): void
435 {
436 // apparently permanent parameters should not be removable,
437 // therefore the line below stays commented:
438 // $this->structure->removePermanentParametersByClass($a_class);
439 $this->structure->removeTemporaryParametersByClass($a_class);
440 }
441
445 public function clearParameterByClass(string $a_class, string $a_parameter): void
446 {
447 $this->structure->removeSingleParameterByClass($a_class, $a_parameter);
448 }
449
453 public function getLinkTarget(
454 object $a_gui_obj,
455 string $a_cmd = null,
456 string $a_anchor = null,
457 bool $is_async = false,
458 bool $has_xml_style = false
459 ): string {
461 $this->getClassByObject($a_gui_obj),
462 $a_cmd,
463 $a_anchor,
464 $is_async,
465 $has_xml_style
466 );
467 }
468
472 public function getLinkTargetByClass(
473 $a_class,
474 string $a_cmd = null,
475 string $a_anchor = null,
476 bool $is_async = false,
477 bool $has_xml_style = false
478 ): string {
479 return $this->getTargetUrl(
480 $a_class,
481 $a_cmd,
482 $a_anchor,
483 $is_async,
484 $has_xml_style
485 ) ?? '';
486 }
487
491 public function getFormAction(
492 object $a_gui_obj,
493 string $a_fallback_cmd = null,
494 string $a_anchor = null,
495 bool $is_async = false,
496 bool $has_xml_style = false
497 ): string {
498 return $this->getFormActionByClass(
499 $this->getClassByObject($a_gui_obj),
500 $a_fallback_cmd,
501 $a_anchor,
502 $is_async,
503 $has_xml_style
504 );
505 }
506
510 public function getFormActionByClass(
511 $a_class,
512 string $a_fallback_cmd = null,
513 string $a_anchor = null,
514 bool $is_async = false,
515 bool $has_xml_style = false
516 ): string {
517 return $this->getTargetUrl(
518 $a_class,
519 $a_fallback_cmd,
520 $a_anchor,
521 $is_async,
522 $has_xml_style,
523 true
524 ) ?? '';
525 }
526
530 public function redirect(
531 object $a_gui_obj,
532 string $a_cmd = null,
533 string $a_anchor = null,
534 bool $is_async = false
535 ): void {
536 $this->redirectByClass(
537 $this->getClassByObject($a_gui_obj),
538 $a_cmd,
539 $a_anchor,
540 $is_async
541 );
542 }
543
547 public function redirectByClass(
548 $a_class,
549 string $a_cmd = null,
550 string $a_anchor = null,
551 bool $is_async = false
552 ): void {
553 $this->redirectToURL(
554 $this->getLinkTargetByClass(
555 $a_class,
556 $a_cmd,
557 $a_anchor,
558 $is_async
559 )
560 );
561 }
562
566 public function redirectToURL(string $target_url): void
567 {
568 // prepend the ILIAS HTTP path if it wasn't already.
569 if (defined("ILIAS_HTTP_PATH") &&
570 strpos($target_url, "://") === false &&
571 strpos($target_url, "/") !== 0
572 ) {
573 $target_url = ILIAS_HTTP_PATH . "/" . $target_url;
574 }
575
576 // this line can be dropped after discussion with TB or JF,
577 // it keeps the functionality of UI plugin hooks alive.
578 $target_url = $this->modifyUrlWithPluginHooks($target_url);
579
580 // initialize http response object
581 $response = new Response();
582
583 // there's an exceptional case for asynchronous file uploads
584 // where a json response is delivered.
585 if ('application/json' === $this->server_request->getHeaderLine('Accept')) {
586 try {
587 $body = Streams::ofString(
588 json_encode(
589 [
590 'redirect_url' => $target_url,
591 'success' => true,
592 'message' => 'called redirect after asynchronous file-upload request.',
593 ],
594 JSON_THROW_ON_ERROR
595 )
596 );
597 } catch (Throwable $exception) {
598 $body = Streams::ofString($exception->getMessage());
599 }
600
601 $response = $response->withBody($body);
602 } else {
603 $response = $response->withAddedHeader('Location', $target_url);
604 }
605
606 // manually trigger session_write_close() due to exceptions stored
607 // in the ILIAS database, otherwise this method is called by exit()
608 // which leads to the exceptions not being written to the database.
609 session_write_close();
610
611 try {
612 $this->response_sender->sendResponse($response);
613 } catch (ResponseSendingException $e) {
614 header("Location: $target_url");
615 if ('application/json' === $this->server_request->getHeaderLine('Accept')) {
616 $content = (null !== $response->getBody()) ?
617 $response->getBody()->getContents() :
618 [];
619
620 echo json_encode($content, JSON_THROW_ON_ERROR);
621 }
622 } catch (Throwable $t) {
623 header("Location: $target_url");
624 echo $t->getMessage();
625 }
626
627 exit;
628 }
629
633 public function setContextObject(int $obj_id, string $obj_type): void
634 {
635 // cannot process object without object type.
636 if (!empty($obj_type)) {
637 $this->context->setObjId($obj_id);
638 $this->context->setObjType($obj_type);
639 }
640 }
641
645 public function getContextObjId(): ?int
646 {
647 return $this->context->getObjId();
648 }
649
653 public function getContextObjType(): ?string
654 {
655 return $this->context->getObjType();
656 }
657
661 public function getCallHistory(): array
662 {
663 return $this->stacktrace;
664 }
665
669 public function lookupClassPath(string $a_class): string
670 {
671 $path = $this->structure->getRelativePathByName($a_class);
672 if (null === $path) {
673 throw new ilCtrlException("Class '$a_class' cannot be found in the control structure.");
674 }
675
676 return $path;
677 }
678
682 public function lookupOriginalClassName(string $a_class): ?string
683 {
684 return $this->structure->getObjNameByName($a_class);
685 }
686
690 public function getClassForClasspath(string $a_class_path): string
691 {
692 $path_info = pathinfo($a_class_path);
693
694 return substr($path_info['basename'], 6, -4);
695 }
696
700 public function setTargetScript(string $a_target_script): void
701 {
702 $this->context->setTargetScript($a_target_script);
703 }
704
708 public function isAsynch(): bool
709 {
710 return $this->context->isAsync();
711 }
712
716 public function setReturn(object $a_gui_obj, string $a_cmd = null): void
717 {
718 $this->setReturnByClass($this->getClassByObject($a_gui_obj), $a_cmd);
719 }
720
724 public function setReturnByClass(string $a_class, string $a_cmd = null): void
725 {
726 $this->structure->setReturnTargetByClass(
727 $a_class,
728 $this->getLinkTargetByClass(
729 $a_class,
730 $a_cmd
731 )
732 );
733 }
734
738 public function returnToParent(object $a_gui_obj, string $a_anchor = null): void
739 {
740 $class_name = $this->getClassByObject($a_gui_obj);
741 $target_url = $this->getParentReturnByClass($class_name);
742
743 // append redirect source to target url.
744 $target_url = $this->appendParameterString(
745 $target_url,
746 self::PARAM_REDIRECT,
747 $class_name
748 );
749
750 // append the provided anchor if necessary.
751 if (null !== $a_anchor) {
752 $target_url .= "#$a_anchor";
753 }
754
755 $this->redirectToURL($target_url);
756 }
757
761 public function getParentReturn(object $a_gui_obj): ?string
762 {
763 return $this->getParentReturnByClass($this->getClassByObject($a_gui_obj));
764 }
765
769 public function getParentReturnByClass(string $a_class): ?string
770 {
771 $path = $this->path_factory->find($this->context, $a_class);
772 if (null !== $path->getCidPath()) {
773 foreach ($path->getCidArray() as $cid) {
774 $current_class = $this->structure->getClassNameByCid($cid);
775 $return_target = $this->structure->getReturnTargetByClass($current_class);
776 if (null !== $return_target) {
777 return $return_target;
778 }
779 }
780 }
781
782 return null;
783 }
784
788 public function getRedirectSource(): ?string
789 {
790 return $this->context->getRedirectSource();
791 }
792
796 public function insertCtrlCalls($a_parent, $a_child, string $a_comp_prefix): void
797 {
798 throw new ilCtrlException(__METHOD__ . " is deprecated and must not be used.");
799 }
800
804 public function checkCurrentPathForClass(string $gui_class): bool
805 {
806 $class_cid = $this->structure->getClassCidByName($gui_class);
807 if (null === $class_cid) {
808 return false;
809 }
810
811 return strpos(
812 $this->context->getPath()->getCidPath() ?? '',
813 $class_cid
814 ) !== false;
815 }
816
820 public function getCurrentClassPath(): array
821 {
822 if (null === $this->context->getPath()->getCidPath()) {
823 return [];
824 }
825
826 $class_paths = [];
827 foreach ($this->context->getPath()->getCidArray(SORT_ASC) as $cid) {
828 $class_paths[] = $this->structure->getObjNameByCid($cid);
829 }
830
831 return $class_paths;
832 }
833
840 private function getQueryParam(string $parameter_name): ?string
841 {
842 if ($this->get_parameters->has($parameter_name)) {
843 return $this->get_parameters->retrieve(
844 $parameter_name,
845 $this->refinery->to()->string()
846 );
847 }
848
849 return null;
850 }
851
855 private function getTableCommand(): ?string
856 {
857 if ($this->post_parameters->has('table_top_cmd')) {
858 return $this->post_parameters->retrieve(
859 'table_top_cmd',
860 $this->refinery->custom()->transformation(function ($item): ?string {
861 return is_array($item) ? key($item) : null;
862 })
863 );
864 }
865 // Button on top of the table
866 if ($this->post_parameters->has('select_cmd2')) {
867 return $this->post_parameters->has('selected_cmd2')
868 ? $this->post_parameters->retrieve('selected_cmd2', $this->refinery->to()->string())
869 : null;
870 }
871 // Button at bottom of the table
872 if ($this->post_parameters->has('select_cmd')) {
873 return $this->post_parameters->has('selected_cmd')
874 ? $this->post_parameters->retrieve('selected_cmd', $this->refinery->to()->string())
875 : null;
876 }
877
878 return null;
879 }
880
885 private function getPostCommand(): ?string
886 {
887 if ($this->post_parameters->has(self::PARAM_CMD)) {
888 return $this->post_parameters->retrieve(
889 self::PARAM_CMD,
890 $this->refinery->custom()->transformation(
891 static function ($value): ?string {
892 if (!empty($value)) {
893 if (is_array($value)) {
894 // this most likely only works by accident, but
895 // the selected or clicked command button will
896 // always be sent as first array entry. This
897 // should definitely be done differently.
898 return (string) array_key_first($value);
899 }
900
901 return (string) $value;
902 }
903
904 return null;
905 }
906 )
907 );
908 }
909
910 return null;
911 }
912
925 private function getTargetUrl(
926 $a_class,
927 string $a_cmd = null,
928 string $a_anchor = null,
929 bool $is_async = false,
930 bool $is_escaped = false,
931 bool $is_post = false
932 ): ?string {
933 if (empty($a_class)) {
934 throw new ilCtrlException(__METHOD__ . " was provided with an empty class or class-array.");
935 }
936
937 $is_array = is_array($a_class);
938
939 $path = $this->path_factory->find($this->context, $a_class);
940 if (null !== ($exception = $path->getException())) {
941 throw $exception;
942 }
943
944 $base_class = $path->getBaseClass();
945 if (null === $base_class) {
946 throw new ilCtrlException("Cannot find a valid baseclass in the cid path '{$path->getCidPath()}'");
947 }
948
949 $target_url = $this->context->getTargetScript();
950 $target_url = $this->appendParameterString(
951 $target_url,
952 self::PARAM_BASE_CLASS,
953 urlencode($base_class), // encode in case of namespaced classes
954 $is_escaped
955 );
956
957 $cmd_class = ($is_array) ?
958 $a_class[array_key_last($a_class)] :
959 $a_class;
960
961 // only append the cid path and command class params
962 // if they exist.
963 if (null !== $path->getNextCid($base_class)) {
964 $target_url = $this->appendParameterString(
965 $target_url,
966 self::PARAM_CID_PATH,
967 $path->getCidPath(),
968 $is_escaped
969 );
970
971 $target_url = $this->appendParameterString(
972 $target_url,
973 self::PARAM_CMD_CLASS,
974 urlencode($cmd_class), // encode in case of namespaced classes
975 $is_escaped
976 );
977 }
978
979 // if the target url is generated for form actions,
980 // the command must be set to 'post'.
981 if ($is_post) {
982 $target_url = $this->appendParameterString(
983 $target_url,
984 self::PARAM_CMD,
985 self::CMD_POST,
986 $is_escaped
987 );
988 }
989
990 // the actual command is appended as fallback command
991 // for form actions and 'normal' get requests.
992 if (!empty($a_cmd)) {
993 $target_url = $this->appendParameterString(
994 $target_url,
995 ($is_post) ? self::PARAM_CMD_FALLBACK : self::PARAM_CMD,
996 $a_cmd,
997 $is_escaped
998 );
999 }
1000
1001 // collect all parameters of classes within the current
1002 // targets path and append them to the target url.
1003 foreach ($path->getCidArray(SORT_ASC) as $cid) {
1004 $class_name = $this->structure->getClassNameByCid($cid);
1005 if (null === $class_name) {
1006 throw new ilCtrlException("Classname for cid '$cid' in current path cannot be found.");
1007 }
1008
1009 $target_url = $this->appendParameterStringsByClass(
1010 $class_name,
1011 $target_url,
1012 $is_escaped
1013 );
1014 }
1015
1016 // append a csrf token if the command is considered
1017 // unsafe or the link is for form actions.
1018 if (!$this->isCmdSecure($is_post, $cmd_class, $a_cmd)) {
1019 $token = $this->token_repository->getToken();
1020 $target_url = $this->appendParameterString(
1021 $target_url,
1022 self::PARAM_CSRF_TOKEN,
1023 $token->getToken(),
1024 $is_escaped
1025 );
1026 }
1027
1028 if ($is_async) {
1029 $target_url = $this->appendParameterString(
1030 $target_url,
1031 self::PARAM_CMD_MODE,
1032 self::CMD_MODE_ASYNC,
1033 $is_escaped
1034 );
1035 }
1036
1037 if (!empty($a_anchor)) {
1038 $target_url .= "#$a_anchor";
1039 }
1040
1041 return $target_url;
1042 }
1043
1050 private function modifyUrlWithPluginHooks(string $target_url): string
1051 {
1052 $ui_plugins = $this->component_factory->getActivePluginsInSlot("uihk");
1053 foreach ($ui_plugins as $plugin_instance) {
1056 $html = $plugin_instance
1057 ->getUIClassInstance()
1058 ->getHTML(
1059 'Services/Utilities',
1060 'redirect',
1061 ["html" => $target_url]
1062 );
1063
1064 if (ilUIHookPluginGUI::KEEP !== $html['mode']) {
1065 $target_url = $plugin_instance
1066 ->getUIClassInstance()
1067 ->modifyHTML(
1068 $target_url,
1069 $html
1070 );
1071 }
1072 }
1073
1074 return $target_url;
1075 }
1076
1084 private function isCmdSecure(bool $is_post, string $cmd_class, string $cmd = null): bool
1085 {
1086 // if no command is specified, the command is
1087 // considered safe if it's not a POST command.
1088 if (null === $cmd) {
1089 return !$is_post;
1090 }
1091
1092 // if the given command class doesn't exist, the
1093 // command is not considered safe as it might've been
1094 // tampered with.
1095 $obj_name = $this->structure->getObjNameByName($cmd_class);
1096 if (null === $obj_name) {
1097 return false;
1098 }
1099
1100 // if the command class does not yet implement the
1101 // ilCtrlSecurityInterface, the command is considered
1102 // safe if it's not a POST command.
1103 if (!is_a($obj_name, ilCtrlSecurityInterface::class, true)) {
1104 return !$is_post;
1105 }
1106
1107 // the post command is considered safe if it's contained
1108 // in the list of safe post commands.
1109 if ($is_post) {
1110 return in_array($cmd, $this->structure->getSafeCommandsByName($cmd_class), true);
1111 }
1112
1113 // the get command is considered safe if it's not
1114 // contained in the list of unsafe get commands.
1115 return !in_array($cmd, $this->structure->getUnsafeCommandsByName($cmd_class), true);
1116 }
1117
1127 string $class_name,
1128 string $target_url,
1129 bool $is_escaped = false
1130 ): string {
1131 $class_parameters = $this->getParameterArrayByClass($class_name);
1132 if (!empty($class_parameters)) {
1133 foreach ($class_parameters as $key => $value) {
1134 $target_url = $this->appendParameterString(
1135 $target_url,
1136 $key,
1137 $value,
1138 $is_escaped
1139 );
1140 }
1141 }
1142
1143 return $target_url;
1144 }
1145
1154 private function appendParameterString(
1155 string $url,
1156 string $parameter_name,
1157 $value,
1158 bool $is_escaped = false
1159 ): string {
1160 // transform value into a string, since null will fail we can
1161 // (temporarily) use the null coalescing operator.
1162 $value = $this->refinery->kindlyTo()->string()->transform($value ?? '');
1163
1164 if ('' === $value) {
1165 return $url;
1166 }
1167
1169 $parsed_url = parse_url(str_replace('&amp;', '&', $url));
1170
1171 $query_parameters = $this->query_parser->parseQueriesOfURL($parsed_url['query'] ?? '');
1172
1173 // update the given parameter or add it to the list.
1174 $query_parameters[$parameter_name] = $value;
1175
1176 $new_url = $parsed_url['path'] ?? $this->context->getTargetScript();
1177 // we currently only escape ampersands (don't blame me).
1178 $ampersand = ($is_escaped) ? '&amp;' : '&';
1179
1180 foreach ($query_parameters as $parameter => $parameter_value) {
1181 $new_url .= (strpos($new_url, '?') !== false) ?
1182 $ampersand . "$parameter=$parameter_value" :
1183 "?$parameter=$parameter_value";
1184 }
1185
1186 return $new_url;
1187 }
1188
1194 private function populateCall(string $class_name, string $cmd_mode): void
1195 {
1196 $obj_name = $this->structure->getObjNameByName($class_name);
1197
1198 $this->stacktrace[] = [
1199 self::PARAM_CMD_CLASS => $obj_name,
1200 self::PARAM_CMD_MODE => $cmd_mode,
1201 self::PARAM_CMD => $this->getCmd(),
1202 ];
1203 }
1204
1211 private function getClassByObject($object): string
1212 {
1213 return (is_object($object)) ? get_class($object) : $object;
1214 }
1215}
static return function(ContainerConfigurator $containerConfigurator)
Definition: basic_rector.php:9
Builds data types.
Definition: Factory.php:21
return true
ilCtrl exceptions
Class ilCtrl provides processing control methods.
getCurrentClassPath()
@inheritDoc
getParentReturn(object $a_gui_obj)
@inheritDoc
populateCall(string $class_name, string $cmd_mode)
Helper function that populates a call in the current stacktrace.
getCallHistory()
@inheritDoc
isCmdSecure(bool $is_post, string $cmd_class, string $cmd=null)
Returns whether a given command is considered safe or not.
setCmdClass($a_cmd_class)
@inheritDoc
getClassForClasspath(string $a_class_path)
@inheritDoc
insertCtrlCalls($a_parent, $a_child, string $a_comp_prefix)
@inheritDoc
getPostCommand()
Returns the current $_POST command.
setCmd(?string $a_cmd)
@inheritDoc
getContextObjId()
@inheritDoc
getHTML(object $a_gui_object, array $a_parameters=null)
@inheritDoc
setContextObject(int $obj_id, string $obj_type)
@inheritDoc
saveParameterByClass(string $a_class, $a_parameter)
@inheritDoc
getLinkTargetByClass( $a_class, string $a_cmd=null, string $a_anchor=null, bool $is_async=false, bool $has_xml_style=false)
@inheritDoc
Refinery $refinery
lookupClassPath(string $a_class)
@inheritDoc
getParameterArrayByClass(string $a_class)
@inheritDoc
RequestWrapper $get_parameters
redirectToURL(string $target_url)
@inheritDoc
setReturnByClass(string $a_class, string $a_cmd=null)
@inheritDoc
ilComponentFactory $component_factory
redirectByClass( $a_class, string $a_cmd=null, string $a_anchor=null, bool $is_async=false)
@inheritDoc
getTableCommand()
ResponseSenderStrategy $response_sender
getQueryParam(string $parameter_name)
Returns a parameter with the given name from the current GET request.
ilCtrlContextInterface $context
returnToParent(object $a_gui_obj, string $a_anchor=null)
@inheritDoc
getCmdClass()
@inheritDoc
getFormActionByClass( $a_class, string $a_fallback_cmd=null, string $a_anchor=null, bool $is_async=false, bool $has_xml_style=false)
@inheritDoc
getNextClass($a_gui_class=null)
@inheritDoc
redirect(object $a_gui_obj, string $a_cmd=null, string $a_anchor=null, bool $is_async=false)
@inheritDoc
getRedirectSource()
@inheritDoc
setParameter(object $a_gui_obj, string $a_parameter, $a_value)
@inheritDoc
RequestWrapper $post_parameters
setReturn(object $a_gui_obj, string $a_cmd=null)
@inheritDoc
clearParameters(object $a_gui_obj)
@inheritDoc
object $exec_object
saveParameter(object $a_gui_obj, $a_parameter)
@inheritDoc
setTargetScript(string $a_target_script)
@inheritDoc
getTargetUrl( $a_class, string $a_cmd=null, string $a_anchor=null, bool $is_async=false, bool $is_escaped=false, bool $is_post=false)
Helper function that returns a target URL string.
getContextObjType()
@inheritDoc
checkCurrentPathForClass(string $gui_class)
@inheritDoc
getClassByObject($object)
Helper function that returns the class name of a mixed (object or string) parameter.
clearParametersByClass(string $a_class)
@inheritDoc
ilCtrlQueryParserInterface $query_parser
getParentReturnByClass(string $a_class)
@inheritDoc
clearParameterByClass(string $a_class, string $a_parameter)
@inheritDoc
ServerRequestInterface $server_request
getCmd(string $fallback_command=null)
@inheritDoc
appendParameterStringsByClass(string $class_name, string $target_url, bool $is_escaped=false)
Appends all parameters for a given class to the given URL.
ilCtrlStructureInterface $structure
ilCtrlTokenRepositoryInterface $token_repository
ilCtrlPathFactoryInterface $path_factory
isAsynch()
@inheritDoc
__construct(ilCtrlStructureInterface $structure, ilCtrlTokenRepositoryInterface $token_repository, ilCtrlPathFactoryInterface $path_factory, ilCtrlContextInterface $context, ResponseSenderStrategy $response_sender, ServerRequestInterface $server_request, RequestWrapper $post_parameters, RequestWrapper $get_parameters, Refinery $refinery, ilComponentFactory $component_factory, ilCtrlQueryParserInterface $query_parser)
ilCtrl Constructor
getLinkTarget(object $a_gui_obj, string $a_cmd=null, string $a_anchor=null, bool $is_async=false, bool $has_xml_style=false)
@inheritDoc
getFormAction(object $a_gui_obj, string $a_fallback_cmd=null, string $a_anchor=null, bool $is_async=false, bool $has_xml_style=false)
@inheritDoc
forwardCommand(object $a_gui_object)
@inheritDoc
setParameterByClass(string $a_class, string $a_parameter, $a_value)
@inheritDoc
getParameterArray(object $a_gui_obj)
@inheritDoc
array $stacktrace
callBaseClass(string $a_base_class=null)
@inheritDoc
lookupOriginalClassName(string $a_class)
@inheritDoc
if(!file_exists(getcwd() . '/ilias.ini.php'))
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: confirmReg.php:20
return['3gp', '7z', 'ai', 'aif', 'aifc', 'aiff', 'au', 'arw', 'avi', 'backup', 'bak', 'bas', 'bpmn', 'bpmn2', 'bmp', 'bib', 'bibtex', 'bz', 'bz2', 'c', 'c++', 'cc', 'cct', 'cdf', 'cer', 'class', 'cls', 'conf', 'cpp', 'crt', 'crs', 'crw', 'cr2', 'css', 'cst', 'csv', 'cur', 'db', 'dcr', 'des', 'dng', 'doc', 'docx', 'dot', 'dotx', 'dtd', 'dvi', 'el', 'eps', 'epub', 'f', 'f77', 'f90', 'flv', 'for', 'g3', 'gif', 'gl', 'gan', 'ggb', 'gsd', 'gsm', 'gtar', 'gz', 'gzip', 'h', 'hpp', 'htm', 'html', 'htmls', 'ibooks', 'ico', 'ics', 'ini', 'ipynb', 'java', 'jbf', 'jpeg', 'jpg', 'js', 'jsf', 'jso', 'json', 'latex', 'lang', 'less', 'log', 'lsp', 'ltx', 'm1v', 'm2a', 'm2v', 'm3u', 'm4a', 'm4v', 'markdown', 'm', 'mat', 'md', 'mdl', 'mdown', 'mid', 'min', 'midi', 'mobi', 'mod', 'mov', 'movie', 'mp2', 'mp3', 'mp4', 'mpa', 'mpeg', 'mpg', 'mph', 'mpga', 'mpp', 'mpt', 'mpv', 'mpx', 'mv', 'mw', 'mv4', 'nb', 'nbp', 'nef', 'nif', 'niff', 'obj', 'obm', 'odt', 'ods', 'odp', 'odg', 'odf', 'oga', 'ogg', 'ogv', 'old', 'p', 'pas', 'pbm', 'pcl', 'pct', 'pcx', 'pdf', 'pgm', 'pic', 'pict', 'png', 'por', 'pov', 'project', 'properties', 'ppa', 'ppm', 'pps', 'ppsx', 'ppt', 'pptx', 'ppz', 'ps', 'psd', 'pwz', 'qt', 'qtc', 'qti', 'qtif', 'r', 'ra', 'ram', 'rar', 'rast', 'rda', 'rev', 'rexx', 'ris', 'rf', 'rgb', 'rm', 'rmd', 'rmi', 'rmm', 'rmp', 'rt', 'rtf', 'rtx', 'rv', 's', 's3m', 'sav', 'sbs', 'sec', 'sdml', 'sgm', 'sgml', 'smi', 'smil', 'srt', 'sps', 'spv', 'stl', 'svg', 'swa', 'swf', 'swz', 'tar', 'tex', 'texi', 'texinfo', 'text', 'tgz', 'tif', 'tiff', 'ttf', 'txt', 'tmp', 'uvproj', 'vdf', 'vimeo', 'viv', 'vivo', 'vrml', 'vsdx', 'wav', 'webm', 'wmv', 'wmx', 'wmz', 'woff', 'wwd', 'xhtml', 'xif', 'xls', 'xlsx', 'xmind', 'xml', 'xsl', 'xsd', 'zip']
Interface RequestWrapper.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Interface ilCtrlPathFactoryInterface describes the ilCtrl Path factory.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Interface ilCtrlTokenRepositoryInterface describes an ilCtrl token.
exit
Definition: login.php:28
$path
Definition: ltiservices.php:32
string $key
Consumer key/client ID value.
Definition: System.php:193
$url
$response
$token
Definition: xapitoken.php:70