ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilLTIViewGUI.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
33{
37 public const CHECK_HTTP_REFERER = true;
38
42 private ?ILIAS\DI\Container $dic = null;
43 private ?int $user = null;
44 private ?ilLogger $log = null;
45 private string $link_dir = "";
46
47 private ?int $effectiveRefId = null;
48 private \ILIAS\HTTP\Wrapper\WrapperFactory $wrapper;
51
55 public ?ilLanguage $lng = null;
56
60 public function __construct()
61 {
62 global $DIC;
63 $this->dic = $DIC;
64 $this->log = ilLoggerFactory::getLogger('ltis');
65 $this->lng = $this->dic->language();
66 $this->lng->loadLanguageModule('lti');
67 $this->wrapper = $DIC->http()->wrapper();
68 $this->kindlyTo = $DIC->refinery()->kindlyTo();
69 $this->locator = $DIC['ilLocator'];
70 }
71
75 public function init(): void
76 {
77 $this->link_dir = (defined("ILIAS_MODULE")) ? "../" : "";
78 if ($this->isLTIUser()) {
79 $context = $this->dic->globalScreen()->tool()->context();
80 $context->claim()->lti();
81 $this->initGUI();
82 }
83 }
84
89 public static function getInstance()
90 {
91 global $DIC;
92 return $DIC["lti"];
93 }
94
99 private function isLTIUser(): bool
100 {
101 if (!$this->dic->user() instanceof ilObjUser) {
102 return false;
103 }
104 if ($this->dic->user()->getAuthMode() == null) {
105 return false;
106 }
107 return (strpos($this->dic->user()->getAuthMode(), 'lti_') === 0);
108 }
109
113 public function executeCommand(): void
114 {
115 global $ilCtrl;
116 $cmd = $ilCtrl->getCmd();
117 switch ($cmd) {
118 case 'exit':
119 $this->exitLti();
120 break;
121 }
122 }
123
127 public function isActive(): bool
128 {
129 return $this->isLTIUser();
130 }
131
135 public function initGUI(): void
136 {
137 $this->log->debug("initGUI");
138 $baseclass = '';
139 $cmdclass = '';
140 if ($this->wrapper->query()->has('baseClass')) {
141 $baseclass = strtolower($this->wrapper->query()->retrieve('baseClass', $this->kindlyTo->string()));
142 }
143 if ($this->wrapper->query()->has('cmdClass')) {
144 $cmdclass = strtolower($this->wrapper->query()->retrieve('cmdClass', $this->kindlyTo->string()));
145 }
146
147 if ($baseclass == 'illtiroutergui') {
148 return;
149 }
150 }
151
155 protected function getContextId(): ?int
156 {
157 global $DIC;
158
159 // forced lti_context_id for example request command in exitLTI
160 if ($this->wrapper->query()->has('lti_context_id') &&
161 $this->wrapper->query()->retrieve('lti_context_id', $this->kindlyTo->string()) !== '') {
162 $contextId = (int) $this->wrapper->query()->retrieve('lti_context_id', $this->kindlyTo->int());
163 $this->log->debug("find context_id by GET param: " . (string) $contextId);
164 return $contextId;
165 }
166
167 $this->findEffectiveRefId();
169 // ???
170 if (empty($ref_id)) {
171 return 0;
172 }
173
174 $this->log->debug("Effective ref_id: " . $ref_id);
175 // context_id = ref_id in request
176 if (ilSession::has('lti_' . $ref_id . '_post_data')) {
177 $this->log->debug("lti context session exists for " . $ref_id);
178 // return $ref_id;
179 }
180 // sub item request
181 $this->log->debug("ref_id not exists as context_id, walking tree backwards to find a valid context_id");
182 $locator_items = $this->locator->getItems();
183 if (is_array($locator_items) && count($locator_items) > 0) {
184 for ($i = count($locator_items) - 1;$i >= 0;$i--) {
185 if (ilSession::has('lti_' . $locator_items[$i]['ref_id'] . '_post_data')) {
186 $this->log->debug("found valid ref_id in locator: " . $locator_items[$i]['ref_id']);
187 return $locator_items[$i]['ref_id'];
188 }
189 }
190 }
191 $this->log->warning("no valid context_id found for ref_id request: " . $ref_id);
192
195 $obj_type = ilObject::_lookupType($ref_id, true);
196 $context_id = 0;
197 $referer = 0;
198
199 // first try to get real http referer
200 if (isset($_SERVER['HTTP_REFERER'])) {
201 $this->findEffectiveRefId($_SERVER['HTTP_REFERER']);
202 } else { // only fallback and not reliable on multiple browser LTi contexts
203 if (ilSession::has('referer_ref_id')) {
204 $this->effectiveRefId = ilSession::get('referer_ref_id');
205 }
206 }
207
208 $referer = (int) $this->effectiveRefId;
209
210 if ($referer > 0) {
211 if (ilSession::has('lti_' . $referer . '_post_data')) {
212 $ref_id = $referer;
213 $context_id = $referer;
214 $obj_type = ilObject::_lookupType($ref_id, true);
215 $this->log->debug("referer obj_type: " . $obj_type);
216 } else {
217 $this->log->debug("search tree of referer...");
218 if ($this->dic->repositoryTree()->isInTree($referer)) {
219 $path = $this->dic->repositoryTree()->getPathId($referer);
220 for ($i = count($path) - 1;$i >= 0;$i--) {
221 if (ilSession::has('lti_' . $path[$i] . '_post_data')) {
222 // redirect to referer, because it is valid
223 $ref_id = $referer;
224 $context_id = $path[$i];
225 $obj_type = ilObject::_lookupType($ref_id, true);
226 break;
227 }
228 }
229 }
230 }
231 }
232 if ($ref_id > 0 && $obj_type != '') {
233 if (
234 (
235 $this->wrapper->query()->has('baseClass') &&
236 $this->wrapper->query()->retrieve('baseClass', $this->kindlyTo->string()) === 'ilDashboardGUI'
237 )
238 &&
239 (
240 $this->wrapper->query()->has('cmdClass') &&
241 $this->wrapper->query()->retrieve('cmdClass', $this->kindlyTo->string()) === 'ilpersonalprofilegui'
242 )
243 ) {
244 return $context_id;
245 }
246 // $this->dic->ui()->mainTemplate()->setOnScreenMessage('failure', $this->lng->txt('permission_denied'), true);
247 $redirect = $this->link_dir . "goto.php?target=" . $obj_type . "_" . $ref_id . "&lti_context_id=" . $context_id;
248 $this->log->debug("redirect: " . $redirect);
249 $DIC->ctrl()->redirectToURL($redirect);
250 }
251 }
252 $lti_context_ids = ilSession::get('lti_context_ids');
253 if (is_array($lti_context_ids) && count($lti_context_ids) > 0) {
254 if (count($lti_context_ids) == 1) {
255 $this->log->debug("using context_id from only LTI session");
256 return $lti_context_ids[0];
257 } else {
258 $this->log->warning("Multiple LTI sessions exists. The context_id can not be clearly detected");
259 }
260 }
261 return null;
262 }
263
267 public function getPostData(): ?array
268 {
269 $context_id = $this->getContextId();
270 if ($context_id == 0) {
271 $this->log->warning("could not find any valid context_id!");
272 return null;
273 }
274 $post_data = ilSession::get('lti_' . $context_id . '_post_data');
275 if (!is_array($post_data)) {
276 $this->log->warning("no session post_data: " . "lti_" . $context_id . "_post_data");
277 return null;
278 }
279 return $post_data;
280 }
281
285 public function getExternalCss(): string
286 {
287 $post_data = $this->getPostData();
288 if ($post_data !== null) {
289 return (isset($post_data['launch_presentation_css_url'])) ? $post_data['launch_presentation_css_url'] : '';
290 }
291 return '';
292 }
293
297 public function getTitle(): string
298 {
299 $post_data = $this->getPostData();
300 if ($post_data !== null) {
301 return (isset($post_data['resource_link_title'])) ? "LTI - " . $post_data['resource_link_title'] : "LTI";
302 }
303 return "LTI";
304 }
305
309 public function getTitleForExitPage(): string
310 {
311 return $this->lng->txt('lti_exited');
312 }
313
317 public function getShortTitle(): string
318 {
319 return $this->lng->txt('lti_mode');
320 }
321
326 public function exitLti(): void
327 {
328 $this->log->info("exitLTI");
329 $force_ilias_logout = false;
330 $context_id = $this->getContextId();
331 if ($context_id == 0) {
332 $this->log->warning("could not find any valid context_id!");
333 $force_ilias_logout = true;
334 }
335 $post_data = $this->getPostData();
336
337 $return_url = '';
338 if (isset($post_data['launch_presentation_return_url'])) {
339 $return_url = $post_data['launch_presentation_return_url'];
340 }
341 $this->removeContextFromSession((string) $context_id);
342
343 if (ilSession::has('lti_' . $context_id . '_post_data')) {
344 ilSession::clear('lti_' . $context_id . '_post_data');
345 $this->log->debug('unset SESSION["' . 'lti_' . $context_id . '_post_data"]');
346 }
347
348 if (!isset($return_url) || $return_url === '') {
349 $cc = $this->dic->globalScreen()->tool()->context()->current();
350 $cc->addAdditionalData(LtiViewLayoutProvider::GS_EXIT_LTI, true);
351 $ui_factory = $this->dic->ui()->factory();
352 $renderer = $this->dic->ui()->renderer();
353 $content = [
354 $ui_factory->messageBox()->info($this->lng->txt('lti_exited_info'))
355 ];
356 $tpl = $this->dic["tpl"];
357 $tpl->setContent($renderer->render($content));
358 $this->logout($force_ilias_logout);
359 $tpl->printToStdout();
360 } else {
361 $this->logout($force_ilias_logout);
362 header('Location: ' . $return_url);
363 }
364 }
365
369 public function logout(bool $force_ilias_logout = false): void
370 {
371 if ($force_ilias_logout) {
372 $this->log->warning("forcing logout ilias session, maybe a broken LTI context");
373 } else {
374 if (is_array(ilSession::get('lti_context_ids')) && count(ilSession::get('lti_context_ids')) > 0) {
375 $this->log->debug("there is another valid consumer session: ilias session logout refused.");
376 return;
377 }
378 }
379 $this->log->info("logout");
380 $this->dic->user()->setAuthMode((string) ilAuthUtils::AUTH_LOCAL);
381 //ilSession::setClosingContext(ilSession::SESSION_CLOSE_USER); // needed?
382 $auth = $this->dic['ilAuthSession'];
383 //$auth->logout(); // needed?
384 // $auth->setExpired($auth::SESSION_AUTH_EXPIRED, ilAuthStatus::STATUS_UNDEFINED);
385 $auth->setExpired(true);
386 session_destroy();
387 ilUtil::setCookie("ilClientId", "");
388 ilUtil::setCookie("PHPSESSID", "");
389 }
390
396 public function getCmdLink(String $cmd): String
397 {
398 global $ilCtrl;
399 $lti_context_id = $this->getContextId();
400 $lti_context_id_param = ($lti_context_id != '') ? "&lti_context_id=" . $lti_context_id : '';
401 $targetScript = "";
402 return $this->link_dir . $targetScript . $this->dic->ctrl()->getLinkTargetByClass(array('illtiroutergui',strtolower(get_class($this))), $cmd) . "&baseClass=illtiroutergui" . $lti_context_id_param;
403 }
404
405 private function getSessionValue(string $sess_key): string
406 {
407 if (ilSession::has($sess_key) && ilSession::get($sess_key) != '') {
408 return ilSession::get($sess_key);
409 } else {
410 return '';
411 }
412 }
413
414 private function getCookieValue(string $cookie_key): string
415 {
416 if ($this->dic->wrapper->cookie()->has($cookie_key) && $this->dic->wrapper->cookie()->retrieve($cookie_key, $this->dic->refinery()->kindlyTo()->string() != '')) {
417 return $this->dic->wrapper->cookie()->retrieve($cookie_key, $this->dic->refinery()->kindlyTo()->string());
418 } else {
419 return '';
420 }
421 }
422
423 private function removeContextFromSession(string $context_id): void
424 {
425 $lti_context_ids = ilSession::get('lti_context_ids');
426 if (is_array($lti_context_ids) && in_array($context_id, $lti_context_ids)) {
427 array_splice($lti_context_ids, array_search($context_id, $lti_context_ids), 1);
428 ilSession::set('lti_context_ids', $lti_context_ids);
429 }
430 }
431
436 private function findEffectiveRefId(?string $url = null): void
437 {
438 $query = [];
439 if ($url === null) {
440 if ($this->wrapper->query()->has('ref_id')) {
441 $query['ref_id'] = $this->wrapper->query()->retrieve('ref_id', $this->kindlyTo->string());
442 }
443 if ($this->wrapper->query()->has('target')) {
444 $query['target'] = $this->wrapper->query()->retrieve('target', $this->kindlyTo->string());
445 }
446 } else {
447 parse_str((string) parse_url($url, PHP_URL_QUERY), $query);
448 }
449 if (isset($query['ref_id']) && (int) $query['ref_id']) {
450 $this->effectiveRefId = (int) $query['ref_id'];
451 return;
452 }
453 if (ilSession::has('lti_init_target') && ilSession::get('lti_init_target') != "") {
454 $target_arr = explode('_', ilSession::get('lti_init_target'));
455 ilSession::set('lti_init_target', "");
456 } else {
457 if (isset($query['target'])) {
458 $target_arr = explode('_', (string) $query['target']);
459 }
460 }
461 if (isset($target_arr[1]) and (int) $target_arr[1]) {
462 $this->effectiveRefId = (int) $target_arr[1];
463 }
464 }
465}
$renderer
Customizing of pimple-DIC for ILIAS.
Definition: Container.php:36
const int AUTH_LOCAL
@classDescription class for ILIAS ViewLTI
getSessionValue(string $sess_key)
removeContextFromSession(string $context_id)
ILIAS Refinery KindlyTo Group $kindlyTo
getCookieValue(string $cookie_key)
logout(bool $force_ilias_logout=false)
logout ILIAS and destroys Session and ilClientId cookie if no consumer is still open in the LTI User ...
findEffectiveRefId(?string $url=null)
Find effective ref_id for request.
isLTIUser()
get LTI Mode from Users->getAuthMode
ILIAS DI Container $dic
private variables
init()
Init LTI mode for lti authenticated users.
ilLanguage $lng
public variables
static getInstance()
for compatiblity with ilLTIRouterGUI
exitLti()
exit LTI session and if defined redirecting to returnUrl ToDo: Standard Template with delos ....
ilLocatorGUI $locator
getCmdLink(String $cmd)
const CHECK_HTTP_REFERER
contstants
ILIAS HTTP Wrapper WrapperFactory $wrapper
language handling
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getLogger(string $a_component_id)
Get component logger.
Component logger with individual log levels by component id.
User class.
static _lookupType(int $id, bool $reference=false)
static get(string $a_var)
static clear(string $a_var)
static set(string $a_var, $a_val)
Set a value.
static has($a_var)
static setCookie(string $a_cookie_name, string $a_cookie_value='', bool $a_also_set_super_global=true, bool $a_set_cookie_invalid=false)
$ref_id
Definition: ltiauth.php:66
$path
Definition: ltiservices.php:30
$_SERVER['HTTP_HOST']
Definition: raiseError.php:26
global $DIC
Definition: shib_login.php:26
$url
Definition: shib_logout.php:68
$context
Definition: webdav.php:31