Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403]
1 <?php 2 3 namespace IMSGlobal\LTI\ToolProvider; 4 5 use IMSGlobal\LTI\ToolProvider\DataConnector\DataConnector; 6 use IMSGlobal\LTI\ToolProvider\Service; 7 use IMSGlobal\LTI\HTTPMessage; 8 use IMSGlobal\LTI\OAuth; 9 use stdClass; 10 11 /** 12 * Class to represent a tool consumer 13 * 14 * @author Stephen P Vickers <svickers@imsglobal.org> 15 * @copyright IMS Global Learning Consortium Inc 16 * @date 2016 17 * @version 3.0.2 18 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 19 */ 20 #[\AllowDynamicProperties] 21 class ToolConsumer 22 { 23 24 /** 25 * Local name of tool consumer. 26 * 27 * @var string $name 28 */ 29 public $name = null; 30 /** 31 * Shared secret. 32 * 33 * @var string $secret 34 */ 35 public $secret = null; 36 /** 37 * LTI version (as reported by last tool consumer connection). 38 * 39 * @var string $ltiVersion 40 */ 41 public $ltiVersion = null; 42 /** 43 * Name of tool consumer (as reported by last tool consumer connection). 44 * 45 * @var string $consumerName 46 */ 47 public $consumerName = null; 48 /** 49 * Tool consumer version (as reported by last tool consumer connection). 50 * 51 * @var string $consumerVersion 52 */ 53 public $consumerVersion = null; 54 /** 55 * Tool consumer GUID (as reported by first tool consumer connection). 56 * 57 * @var string $consumerGuid 58 */ 59 public $consumerGuid = null; 60 /** 61 * Optional CSS path (as reported by last tool consumer connection). 62 * 63 * @var string $cssPath 64 */ 65 public $cssPath = null; 66 /** 67 * Whether the tool consumer instance is protected by matching the consumer_guid value in incoming requests. 68 * 69 * @var boolean $protected 70 */ 71 public $protected = false; 72 /** 73 * Whether the tool consumer instance is enabled to accept incoming connection requests. 74 * 75 * @var boolean $enabled 76 */ 77 public $enabled = false; 78 /** 79 * Date/time from which the the tool consumer instance is enabled to accept incoming connection requests. 80 * 81 * @var int $enableFrom 82 */ 83 public $enableFrom = null; 84 /** 85 * Date/time until which the tool consumer instance is enabled to accept incoming connection requests. 86 * 87 * @var int $enableUntil 88 */ 89 public $enableUntil = null; 90 /** 91 * Date of last connection from this tool consumer. 92 * 93 * @var int $lastAccess 94 */ 95 public $lastAccess = null; 96 /** 97 * Default scope to use when generating an Id value for a user. 98 * 99 * @var int $idScope 100 */ 101 public $idScope = ToolProvider::ID_SCOPE_ID_ONLY; 102 /** 103 * Default email address (or email domain) to use when no email address is provided for a user. 104 * 105 * @var string $defaultEmail 106 */ 107 public $defaultEmail = ''; 108 /** 109 * Setting values (LTI parameters, custom parameters and local parameters). 110 * 111 * @var array $settings 112 */ 113 public $settings = null; 114 /** 115 * Date/time when the object was created. 116 * 117 * @var int $created 118 */ 119 public $created = null; 120 /** 121 * Date/time when the object was last updated. 122 * 123 * @var int $updated 124 */ 125 public $updated = null; 126 /** 127 * The consumer profile data. 128 * 129 * @var stdClass 130 */ 131 public $profile = null; 132 133 /** 134 * Consumer ID value. 135 * 136 * @var int $id 137 */ 138 private $id = null; 139 /** 140 * Consumer key value. 141 * 142 * @var string $key 143 */ 144 private $key = null; 145 /** 146 * Whether the settings value have changed since last saved. 147 * 148 * @var boolean $settingsChanged 149 */ 150 private $settingsChanged = false; 151 /** 152 * Data connector object or string. 153 * 154 * @var mixed $dataConnector 155 */ 156 private $dataConnector = null; 157 158 /** 159 * Class constructor. 160 * 161 * @param string $key Consumer key 162 * @param DataConnector $dataConnector A data connector object 163 * @param boolean $autoEnable true if the tool consumers is to be enabled automatically (optional, default is false) 164 */ 165 public function __construct($key = null, $dataConnector = null, $autoEnable = false) 166 { 167 168 $this->initialize(); 169 if (empty($dataConnector)) { 170 $dataConnector = DataConnector::getDataConnector(); 171 } 172 $this->dataConnector = $dataConnector; 173 if (!empty($key)) { 174 $this->load($key, $autoEnable); 175 } else { 176 $this->secret = DataConnector::getRandomString(32); 177 } 178 179 } 180 181 /** 182 * Initialise the tool consumer. 183 */ 184 public function initialize() 185 { 186 187 $this->id = null; 188 $this->key = null; 189 $this->name = null; 190 $this->secret = null; 191 $this->ltiVersion = null; 192 $this->consumerName = null; 193 $this->consumerVersion = null; 194 $this->consumerGuid = null; 195 $this->profile = null; 196 $this->toolProxy = null; 197 $this->settings = array(); 198 $this->protected = false; 199 $this->enabled = false; 200 $this->enableFrom = null; 201 $this->enableUntil = null; 202 $this->lastAccess = null; 203 $this->idScope = ToolProvider::ID_SCOPE_ID_ONLY; 204 $this->defaultEmail = ''; 205 $this->created = null; 206 $this->updated = null; 207 208 } 209 210 /** 211 * Initialise the tool consumer. 212 * 213 * Pseudonym for initialize(). 214 */ 215 public function initialise() 216 { 217 218 $this->initialize(); 219 220 } 221 222 /** 223 * Save the tool consumer to the database. 224 * 225 * @return boolean True if the object was successfully saved 226 */ 227 public function save() 228 { 229 230 $ok = $this->dataConnector->saveToolConsumer($this); 231 if ($ok) { 232 $this->settingsChanged = false; 233 } 234 235 return $ok; 236 237 } 238 239 /** 240 * Delete the tool consumer from the database. 241 * 242 * @return boolean True if the object was successfully deleted 243 */ 244 public function delete() 245 { 246 247 return $this->dataConnector->deleteToolConsumer($this); 248 249 } 250 251 /** 252 * Get the tool consumer record ID. 253 * 254 * @return int Consumer record ID value 255 */ 256 public function getRecordId() 257 { 258 259 return $this->id; 260 261 } 262 263 /** 264 * Sets the tool consumer record ID. 265 * 266 * @param int $id Consumer record ID value 267 */ 268 public function setRecordId($id) 269 { 270 271 $this->id = $id; 272 273 } 274 275 /** 276 * Get the tool consumer key. 277 * 278 * @return string Consumer key value 279 */ 280 public function getKey() 281 { 282 283 return $this->key; 284 285 } 286 287 /** 288 * Set the tool consumer key. 289 * 290 * @param string $key Consumer key value 291 */ 292 public function setKey($key) 293 { 294 295 $this->key = $key; 296 297 } 298 299 /** 300 * Get the data connector. 301 * 302 * @return mixed Data connector object or string 303 */ 304 public function getDataConnector() 305 { 306 307 return $this->dataConnector; 308 309 } 310 311 /** 312 * Is the consumer key available to accept launch requests? 313 * 314 * @return boolean True if the consumer key is enabled and within any date constraints 315 */ 316 public function getIsAvailable() 317 { 318 319 $ok = $this->enabled; 320 321 $now = time(); 322 if ($ok && !is_null($this->enableFrom)) { 323 $ok = $this->enableFrom <= $now; 324 } 325 if ($ok && !is_null($this->enableUntil)) { 326 $ok = $this->enableUntil > $now; 327 } 328 329 return $ok; 330 331 } 332 333 /** 334 * Get a setting value. 335 * 336 * @param string $name Name of setting 337 * @param string $default Value to return if the setting does not exist (optional, default is an empty string) 338 * 339 * @return string Setting value 340 */ 341 public function getSetting($name, $default = '') 342 { 343 344 if (array_key_exists($name, $this->settings)) { 345 $value = $this->settings[$name]; 346 } else { 347 $value = $default; 348 } 349 350 return $value; 351 352 } 353 354 /** 355 * Set a setting value. 356 * 357 * @param string $name Name of setting 358 * @param string $value Value to set, use an empty value to delete a setting (optional, default is null) 359 */ 360 public function setSetting($name, $value = null) 361 { 362 363 $old_value = $this->getSetting($name); 364 if ($value !== $old_value) { 365 if (!empty($value)) { 366 $this->settings[$name] = $value; 367 } else { 368 unset($this->settings[$name]); 369 } 370 $this->settingsChanged = true; 371 } 372 373 } 374 375 /** 376 * Get an array of all setting values. 377 * 378 * @return array Associative array of setting values 379 */ 380 public function getSettings() 381 { 382 383 return $this->settings; 384 385 } 386 387 /** 388 * Set an array of all setting values. 389 * 390 * @param array $settings Associative array of setting values 391 */ 392 public function setSettings($settings) 393 { 394 395 $this->settings = $settings; 396 397 } 398 399 /** 400 * Save setting values. 401 * 402 * @return boolean True if the settings were successfully saved 403 */ 404 public function saveSettings() 405 { 406 407 if ($this->settingsChanged) { 408 $ok = $this->save(); 409 } else { 410 $ok = true; 411 } 412 413 return $ok; 414 415 } 416 417 /** 418 * Check if the Tool Settings service is supported. 419 * 420 * @return boolean True if this tool consumer supports the Tool Settings service 421 */ 422 public function hasToolSettingsService() 423 { 424 425 $url = $this->getSetting('custom_system_setting_url'); 426 427 return !empty($url); 428 429 } 430 431 /** 432 * Get Tool Settings. 433 * 434 * @param boolean $simple True if all the simple media type is to be used (optional, default is true) 435 * 436 * @return mixed The array of settings if successful, otherwise false 437 */ 438 public function getToolSettings($simple = true) 439 { 440 441 $url = $this->getSetting('custom_system_setting_url'); 442 $service = new Service\ToolSettings($this, $url, $simple); 443 $response = $service->get(); 444 445 return $response; 446 447 } 448 449 /** 450 * Perform a Tool Settings service request. 451 * 452 * @param array $settings An associative array of settings (optional, default is none) 453 * 454 * @return boolean True if action was successful, otherwise false 455 */ 456 public function setToolSettings($settings = array()) 457 { 458 459 $url = $this->getSetting('custom_system_setting_url'); 460 $service = new Service\ToolSettings($this, $url); 461 $response = $service->set($settings); 462 463 return $response; 464 465 } 466 467 /** 468 * Add the OAuth signature to an LTI message. 469 * 470 * @param string $url URL for message request 471 * @param string $type LTI message type 472 * @param string $version LTI version 473 * @param array $params Message parameters 474 * 475 * @return array Array of signed message parameters 476 */ 477 public function signParameters($url, $type, $version, $params) 478 { 479 480 if (!empty($url)) { 481 // Check for query parameters which need to be included in the signature 482 $queryParams = array(); 483 $queryString = parse_url($url, PHP_URL_QUERY); 484 if (!is_null($queryString)) { 485 $queryItems = explode('&', $queryString); 486 foreach ($queryItems as $item) { 487 if (strpos($item, '=') !== false) { 488 list($name, $value) = explode('=', $item); 489 $queryParams[urldecode($name)] = urldecode($value); 490 } else { 491 $queryParams[urldecode($item)] = ''; 492 } 493 } 494 } 495 $params = $params + $queryParams; 496 // Add standard parameters 497 $params['lti_version'] = $version; 498 $params['lti_message_type'] = $type; 499 $params['oauth_callback'] = 'about:blank'; 500 // Add OAuth signature 501 $hmacMethod = new OAuth\OAuthSignatureMethod_HMAC_SHA1(); 502 $consumer = new OAuth\OAuthConsumer($this->getKey(), $this->secret, null); 503 $req = OAuth\OAuthRequest::from_consumer_and_token($consumer, null, 'POST', $url, $params); 504 $req->sign_request($hmacMethod, $consumer, null); 505 $params = $req->get_parameters(); 506 // Remove parameters being passed on the query string 507 foreach (array_keys($queryParams) as $name) { 508 unset($params[$name]); 509 } 510 } 511 512 return $params; 513 514 } 515 516 /** 517 * Add the OAuth signature to an array of message parameters or to a header string. 518 * 519 * @return mixed Array of signed message parameters or header string 520 */ 521 public static function addSignature($endpoint, $consumerKey, $consumerSecret, $data, $method = 'POST', $type = null) 522 { 523 524 $params = array(); 525 if (is_array($data)) { 526 $params = $data; 527 } 528 // Check for query parameters which need to be included in the signature 529 $queryParams = array(); 530 $queryString = parse_url($endpoint, PHP_URL_QUERY); 531 if (!is_null($queryString)) { 532 $queryItems = explode('&', $queryString); 533 foreach ($queryItems as $item) { 534 if (strpos($item, '=') !== false) { 535 list($name, $value) = explode('=', $item); 536 $queryParams[urldecode($name)] = urldecode($value); 537 } else { 538 $queryParams[urldecode($item)] = ''; 539 } 540 } 541 $params = $params + $queryParams; 542 } 543 544 if (!is_array($data)) { 545 // Calculate body hash 546 $hash = base64_encode(sha1($data, true)); 547 $params['oauth_body_hash'] = $hash; 548 } 549 550 // Add OAuth signature 551 $hmacMethod = new OAuth\OAuthSignatureMethod_HMAC_SHA1(); 552 $oauthConsumer = new OAuth\OAuthConsumer($consumerKey, $consumerSecret, null); 553 $oauthReq = OAuth\OAuthRequest::from_consumer_and_token($oauthConsumer, null, $method, $endpoint, $params); 554 $oauthReq->sign_request($hmacMethod, $oauthConsumer, null); 555 $params = $oauthReq->get_parameters(); 556 // Remove parameters being passed on the query string 557 foreach (array_keys($queryParams) as $name) { 558 unset($params[$name]); 559 } 560 561 if (!is_array($data)) { 562 $header = $oauthReq->to_header(); 563 if (empty($data)) { 564 if (!empty($type)) { 565 $header .= "\nAccept: {$type}"; 566 } 567 } else if (isset($type)) { 568 $header .= "\nContent-Type: {$type}"; 569 $header .= "\nContent-Length: " . strlen($data); 570 } 571 return $header; 572 } else { 573 return $params; 574 } 575 576 } 577 578 /** 579 * Perform a service request 580 * 581 * @param object $service Service object to be executed 582 * @param string $method HTTP action 583 * @param string $format Media type 584 * @param mixed $data Array of parameters or body string 585 * 586 * @return HTTPMessage HTTP object containing request and response details 587 */ 588 public function doServiceRequest($service, $method, $format, $data) 589 { 590 591 $header = ToolConsumer::addSignature($service->endpoint, $this->getKey(), $this->secret, $data, $method, $format); 592 593 // Connect to tool consumer 594 $http = new HTTPMessage($service->endpoint, $method, $data, $header); 595 // Parse JSON response 596 if ($http->send() && !empty($http->response)) { 597 $http->responseJson = json_decode($http->response); 598 $http->ok = !is_null($http->responseJson); 599 } 600 601 return $http; 602 603 } 604 605 /** 606 * Load the tool consumer from the database by its record ID. 607 * 608 * @param string $id The consumer key record ID 609 * @param DataConnector $dataConnector Database connection object 610 * 611 * @return object ToolConsumer The tool consumer object 612 */ 613 public static function fromRecordId($id, $dataConnector) 614 { 615 616 $toolConsumer = new ToolConsumer(null, $dataConnector); 617 618 $toolConsumer->initialize(); 619 $toolConsumer->setRecordId($id); 620 if (!$dataConnector->loadToolConsumer($toolConsumer)) { 621 $toolConsumer->initialize(); 622 } 623 624 return $toolConsumer; 625 626 } 627 628 629 ### 630 ### PRIVATE METHOD 631 ### 632 633 /** 634 * Load the tool consumer from the database. 635 * 636 * @param string $key The consumer key value 637 * @param boolean $autoEnable True if the consumer should be enabled (optional, default if false) 638 * 639 * @return boolean True if the consumer was successfully loaded 640 */ 641 private function load($key, $autoEnable = false) 642 { 643 644 $this->key = $key; 645 $ok = $this->dataConnector->loadToolConsumer($this); 646 if (!$ok) { 647 $this->enabled = $autoEnable; 648 } 649 650 return $ok; 651 652 } 653 654 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body