This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** Toolbox class */ |
||
3 | |||
4 | namespace smtech\ReflexiveCanvasLTI; |
||
5 | |||
6 | use mysqli; |
||
7 | use Serializable; |
||
8 | |||
9 | use Log; |
||
10 | |||
11 | use Battis\AppMetadata; |
||
12 | use Battis\ConfigXML; |
||
13 | use Battis\DataUtilities; |
||
14 | |||
15 | use smtech\CanvasPest\CanvasPest; |
||
16 | use smtech\ReflexiveCanvasLTI\LTI\ToolProvider; |
||
17 | use smtech\ReflexiveCanvasLTI\Exception\ConfigurationException; |
||
18 | use smtech\LTI\Configuration\Generator; |
||
19 | use smtech\LTI\Configuration\LaunchPrivacy; |
||
20 | use smtech\LTI\Configuration\Exception\ConfigurationException as LTIConfigGeneratorException; |
||
21 | |||
22 | /** |
||
23 | * A toolbox of tools for quickly constructing LTI tool providers that hook |
||
24 | * back into the Canvas API reflexively. |
||
25 | * |
||
26 | * The basic idea is that you need an XML configuration file of credentials and |
||
27 | * use that to instantiate the Toolbox. The toolbox can then perform LTI |
||
28 | * authentication, handle API requests, generate an LTI Configuration XML file, |
||
29 | * etc. for you. |
||
30 | * |
||
31 | * @author Seth Battis |
||
32 | * @version v1.0 |
||
33 | */ |
||
34 | class Toolbox implements Serializable |
||
35 | { |
||
36 | /** Default level of information-sharing privacy between consumer and provider */ |
||
37 | const DEFAULT_LAUNCH_PRIVACY = 'public'; |
||
38 | |||
39 | /** Name of the database table backing the tool metadata */ |
||
40 | const TOOL_METADATA_TABLE = 'tool_metadata'; |
||
41 | |||
42 | /** The path to the configuration file from which this toolbox was generated */ |
||
43 | const TOOL_CONFIG_FILE = 'TOOL_CONFIG_FILE'; |
||
44 | |||
45 | /** |
||
46 | * The (ideally globally unique) identifier for the LTI tool provider |
||
47 | */ |
||
48 | const TOOL_ID = 'TOOL_ID'; |
||
49 | |||
50 | /** The human-readable name of the tool */ |
||
51 | const TOOL_NAME = 'TOOL_NAME'; |
||
52 | |||
53 | /** The human-readable description of the tool */ |
||
54 | const TOOL_DESCRIPTION = 'TOOL_DESCRIPTION'; |
||
55 | |||
56 | /** The URL of the tool's icon image (if present) */ |
||
57 | const TOOL_ICON_URL = 'TOOL_ICON_URL'; |
||
58 | |||
59 | /** The domain from which Tool Consumer requests may emanate for the tool */ |
||
60 | const TOOL_DOMAIN = 'TOOL_DOMAIN'; |
||
61 | |||
62 | /** The URL of the script that will handle LTI authentication */ |
||
63 | const TOOL_LAUNCH_URL = 'TOOL_LAUNCH_URL'; |
||
64 | |||
65 | /** The level of information sharing between the LMS and the tool */ |
||
66 | const TOOL_LAUNCH_PRIVACY = 'TOOL_LAUNCH_PRIVACY'; |
||
67 | |||
68 | /** The path to the tool's log file */ |
||
69 | const TOOL_LOG = 'TOOL_LOG'; |
||
70 | |||
71 | /** An associative array of LTI request types and the URL that handles that request. */ |
||
72 | const TOOL_HANDLER_URLS = 'TOOL_HANDLER_URLS'; |
||
73 | |||
74 | /** An associative array of Canvas API credentials (`url` and `token`) */ |
||
75 | const TOOL_CANVAS_API = 'TOOL_CANVAS_API'; |
||
76 | |||
77 | /** |
||
78 | * Persistent metadata storage |
||
79 | * @var AppMetadata |
||
80 | * @see Toolbox::config() Toolbox::config() |
||
81 | */ |
||
82 | protected $metadata = false; |
||
83 | |||
84 | /** |
||
85 | * Object-oriented access to the Canvas API |
||
86 | * @var CanvasPest |
||
87 | */ |
||
88 | protected $api = false; |
||
89 | |||
90 | /** |
||
91 | * MySQL database connection |
||
92 | * @var mysqli |
||
93 | */ |
||
94 | protected $mysql = false; |
||
95 | |||
96 | /** |
||
97 | * LTI Tool Provider for handling authentication and consumer/user management |
||
98 | * @var ToolProvider |
||
99 | */ |
||
100 | protected $toolProvider; |
||
101 | |||
102 | /** |
||
103 | * Generator for LTI Configuration XML files |
||
104 | * @var Generator |
||
105 | */ |
||
106 | protected $generator; |
||
107 | |||
108 | /** |
||
109 | * Log file manager |
||
110 | * @var Log |
||
111 | */ |
||
112 | protected $logger = false; |
||
113 | |||
114 | /** |
||
115 | * Queue of delayed log messages (waiting for a logger instance) |
||
116 | * @return array |
||
117 | */ |
||
118 | protected $logQueue = []; |
||
119 | |||
120 | /** |
||
121 | * Provide serialization support for the Toolbox |
||
122 | * |
||
123 | * This allows a Toolbox to be stored in the `$_SESSION` variables. |
||
124 | * |
||
125 | * Caveat emptor: because `mysqli` objects can not be serialized, |
||
126 | * serialization is limited to storing a reference to the configuration file |
||
127 | * that generated this object, which will be reaccessed (along with cached |
||
128 | * configuration metadata) when the object is unserialized. |
||
129 | * |
||
130 | * @return string |
||
131 | */ |
||
132 | public function serialize() |
||
133 | { |
||
134 | return serialize([ |
||
135 | 'config' => $this->config(static::TOOL_CONFIG_FILE) |
||
136 | ]); |
||
137 | } |
||
138 | |||
139 | /** |
||
140 | * Provide serialization support for Toolbox |
||
141 | * |
||
142 | * This allows a Toolbox to be stored in the `$_SESSION` variables. |
||
143 | * |
||
144 | * @see Toolbox::serialize() `Toolbox::serialize()` has more information on the |
||
145 | * specifics of the serialization approach. |
||
146 | * |
||
147 | * @param string $serialized A Toolbox object serialized by `Toolbox::serialize()` |
||
148 | * @return Toolbox |
||
149 | */ |
||
150 | public function unserialize($serialized) |
||
151 | { |
||
152 | $data = unserialize($serialized); |
||
153 | $this->loadConfiguration($data['config']); |
||
154 | } |
||
155 | |||
156 | /** |
||
157 | * Create a Toolbox instance from a configuration file |
||
158 | * |
||
159 | * @param string $configFilePath Path to the configuration file |
||
160 | * @param boolean $forceRecache Whether or not to rely on cached |
||
161 | * configuration metadata or to force a refresh from the configuration |
||
162 | * file |
||
163 | * @return Toolbox |
||
164 | */ |
||
165 | public static function fromConfiguration($configFilePath, $forceRecache = false) |
||
166 | { |
||
167 | return new static($configFilePath, $forceRecache); |
||
168 | } |
||
169 | |||
170 | /** |
||
171 | * Construct a Toolbox instance from a configuration file |
||
172 | * |
||
173 | * @see Toolbox::fromConfiguration() Use `Toolbox::fromConfiguration()` |
||
174 | * |
||
175 | * @param string $configFilePath |
||
176 | * @param boolean $forceRecache |
||
177 | */ |
||
178 | private function __construct($configFilePath, $forceRecache = false) |
||
179 | { |
||
180 | $this->loadConfiguration($configFilePath, $forceRecache); |
||
181 | } |
||
182 | |||
183 | /** |
||
184 | * Update a Toolbox instance from a configuration file |
||
185 | * |
||
186 | * @see Toolbox::fromConfiguration() Use `Toolbox::fromConfiguration()` |
||
187 | * |
||
188 | * @param string $configFilePath |
||
189 | * @param boolean $forceRecache |
||
190 | * @return void |
||
191 | */ |
||
192 | protected function loadConfiguration($configFilePath, $forceRecache = false) |
||
193 | { |
||
194 | /* load the configuration file */ |
||
195 | $config = new ConfigXML($configFilePath); |
||
196 | |||
197 | /* configure database connections */ |
||
198 | $this->setMySQL($config->newInstanceOf(mysqli::class, '/config/mysql')); |
||
199 | |||
200 | /* configure metadata caching */ |
||
201 | $id = $config->toString('/config/tool/id'); |
||
202 | if (empty($id)) { |
||
203 | $id = basename(dirname($configFilePath)) . '_' . md5(__DIR__ . file_get_contents($configFilePath)); |
||
204 | $this->log(" Automatically generated ID $id"); |
||
205 | } |
||
206 | $this->setMetadata(new AppMetadata($this->mysql, $id, self::TOOL_METADATA_TABLE)); |
||
207 | |||
208 | /* is this the same config file we've been using, or a different one? */ |
||
209 | if ($this->config(static::TOOL_CONFIG_FILE) != $configFilePath) { |
||
210 | $this->log('Provided config file path does not match ' . $this->config(static::TOOL_CONFIG_FILE)); |
||
211 | $forceRecache = true; |
||
212 | } |
||
213 | if ($forceRecache) { |
||
214 | $this->log("Resetting LTI configuration from provided config $configFilePath"); |
||
215 | $this->config(static::TOOL_CONFIG_FILE, realpath($configFilePath)); |
||
216 | } |
||
217 | |||
218 | /* update metadata */ |
||
219 | if ($forceRecache || |
||
220 | empty($this->config(static::TOOL_ID)) || |
||
221 | empty($this->config(static::TOOL_LAUNCH_URL)) || |
||
222 | empty($this->config(static::TOOL_CONFIG_FILE))) { |
||
223 | $this->configToolMetadata($config, $id); |
||
224 | } |
||
225 | |||
226 | /* configure logging */ |
||
227 | if ($forceRecache || empty($this->config(static::TOOL_LOG))) { |
||
228 | $this->configLog($config); |
||
229 | } |
||
230 | $this->setLog(Log::singleton('file', $this->config(static::TOOL_LOG))); |
||
231 | |||
232 | /* configure tool provider */ |
||
233 | if ($forceRecache || empty($this->config(static::TOOL_HANDLER_URLS))) { |
||
234 | $this->configToolProvider($config); |
||
235 | } |
||
236 | |||
237 | /* configure API access */ |
||
238 | if ($forceRecache || empty($this->config(static::TOOL_CANVAS_API))) { |
||
239 | $this->configApi($config); |
||
240 | } |
||
241 | } |
||
242 | |||
243 | /** |
||
244 | * Configure the tool metadata from a configuration file |
||
245 | * @param ConfigXML $config Configuration file object |
||
246 | * @param string $id Unique, potentially auto-generated tool ID |
||
247 | * @return void |
||
248 | */ |
||
249 | protected function configToolMetadata(ConfigXML $config, $id) |
||
250 | { |
||
251 | $tool = $config->toArray('/config/tool')[0]; |
||
252 | |||
253 | $this->config(static::TOOL_ID, $id); |
||
254 | $this->config(static::TOOL_NAME, (empty($tool['name']) ? $id : $tool['name'])); |
||
255 | $configPath = dirname($this->config(static::TOOL_CONFIG_FILE)); |
||
256 | |||
257 | $params = [ |
||
258 | 'description' => static::TOOL_DESCRIPTION, |
||
259 | 'icon' => static::TOOL_ICON_URL, |
||
260 | 'domain' => static::TOOL_DOMAIN, |
||
261 | 'launch-privacy' => static::TOOL_LAUNCH_PRIVACY, |
||
262 | 'authenticate' => static::TOOL_LAUNCH_URL |
||
263 | ]; |
||
264 | |||
265 | foreach ($params as $src => $dest) { |
||
266 | if (empty($tool[$src])) { |
||
267 | $this->clearConfig($dest); |
||
268 | } else { |
||
269 | if (substr($dest, -4) == '_URL') { |
||
270 | $this->config($dest, DataUtilities::URLfromPath( |
||
271 | $tool[$src], |
||
272 | $_SERVER, |
||
273 | $configPath) |
||
274 | ); |
||
275 | } else { |
||
276 | $this->config($dest, $tool[$src]); |
||
277 | } |
||
278 | } |
||
279 | } |
||
280 | |||
281 | if (empty($this->config(static::TOOL_LAUNCH_PRIVACY))) { |
||
282 | $this->config(static::TOOL_LAUNCH_PRIVACY, static::DEFAULT_LAUNCH_PRIVACY); |
||
283 | } |
||
284 | |||
285 | if (empty($this->config(static::TOOL_LAUNCH_URL))) { |
||
286 | $this->config(static::TOOL_LAUNCH_URL, DataUtilities::URLfromPath($_SERVER['SCRIPT_FILENAME'])); |
||
287 | } |
||
288 | |||
289 | $this->log('Tool metadata configured'); |
||
290 | } |
||
291 | |||
292 | /** |
||
293 | * Configure the logger object from a configuration file |
||
294 | * |
||
295 | * This will also flush any backlog of queued messages that have been |
||
296 | * waiting for a logger object to be ready. |
||
297 | * |
||
298 | * @param ConfigXML $config Configuration file object |
||
299 | * @return void |
||
300 | */ |
||
301 | protected function configLog(ConfigXML $config) |
||
302 | { |
||
303 | $configPath = dirname($this->config(static::TOOL_CONFIG_FILE)); |
||
304 | $log = "$configPath/" . $config->toString('/config/tool/log'); |
||
305 | shell_exec("touch \"$log\""); |
||
306 | $this->config(static::TOOL_LOG, realpath($log)); |
||
307 | $this->flushLogQueue(); |
||
308 | } |
||
309 | |||
310 | /** |
||
311 | * Configure tool provider object from configuration file |
||
312 | * @param ConfigXML $config Configuration file object |
||
313 | * @return void |
||
314 | */ |
||
315 | protected function configToolProvider(ConfigXML $config) |
||
316 | { |
||
317 | $handlers = $config->toArray('/config/tool/handlers')[0]; |
||
318 | if (empty($handlers) || !is_array($handlers)) { |
||
319 | throw new ConfigurationException( |
||
320 | 'At least one handler/URL pair must be specified', |
||
321 | ConfigurationException::TOOL_PROVIDER |
||
322 | ); |
||
323 | } |
||
324 | foreach ($handlers as $request => $path) { |
||
325 | $handlers[$request] = DataUtilities::URLfromPath( |
||
326 | dirname($this->config(static::TOOL_CONFIG_FILE)) . "/$path" |
||
327 | ); |
||
328 | } |
||
329 | $this->config(static::TOOL_HANDLER_URLS, $handlers); |
||
330 | $this->log('Tool provider handler URLs configured'); |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * Configure API access object from configuration file |
||
335 | * @param ConfigXML $config Configuration file object |
||
336 | * @return void |
||
337 | */ |
||
338 | protected function configApi(ConfigXML $config) |
||
339 | { |
||
340 | $this->config(static::TOOL_CANVAS_API, $config->toArray('/config/canvas')[0]); |
||
341 | if (empty($this->config(static::TOOL_CANVAS_API))) { |
||
342 | throw new ConfigurationException( |
||
343 | 'Canvas API credentials must be provided', |
||
344 | ConfigurationException::CANVAS_API_MISSING |
||
345 | ); |
||
346 | } |
||
347 | $this->log('Canvas API credentials configured'); |
||
348 | } |
||
349 | |||
350 | /** |
||
351 | * Update toolbox configuration metadata object |
||
352 | * |
||
353 | * @param AppMetadata $metadata |
||
354 | */ |
||
355 | public function setMetadata(AppMetadata $metadata) |
||
356 | { |
||
357 | $this->metadata = $metadata; |
||
358 | } |
||
359 | |||
360 | /** |
||
361 | * Get the toolbox configuration metadata object |
||
362 | * |
||
363 | * @return AppMetadata |
||
364 | */ |
||
365 | public function getMetadata() |
||
366 | { |
||
367 | return $this->metadata; |
||
368 | } |
||
369 | |||
370 | /** |
||
371 | * Access or update a specific configuration metadata key/value pair |
||
372 | * |
||
373 | * The `TOOL_*` constants refer to keys used by the Toolbox by default. |
||
374 | * |
||
375 | * @param string $key The metadata key to look up/create/update |
||
376 | * @param mixed $value (Optional) If not present (or `null`), the current |
||
377 | * metadata is returned. If present, the metadata is created/updated |
||
378 | * @return mixed If not updating the metadata, the metadata (if any) |
||
379 | * currently stored |
||
380 | */ |
||
381 | public function config($key, $value = null) |
||
382 | { |
||
383 | if ($value !== null) { |
||
384 | $this->metadata[$key] = $value; |
||
385 | } elseif (isset($this->metadata[$key])) { |
||
386 | return $this->metadata[$key]; |
||
387 | } else { |
||
388 | return null; |
||
389 | } |
||
390 | } |
||
391 | |||
392 | /** |
||
393 | * Wipe a particular configuration key from storage |
||
394 | * @param string $key |
||
395 | * @return boolean `TRUE` if cleared, `FALSE` if not found |
||
396 | */ |
||
397 | public function clearConfig($key) |
||
398 | { |
||
399 | if (isset($this->metadata[$key])) { |
||
400 | unset($this->metadata[$key]); |
||
401 | return true; |
||
402 | } |
||
403 | return false; |
||
404 | } |
||
405 | |||
406 | |||
407 | /** |
||
408 | * Reset PHP session |
||
409 | * |
||
410 | * Handy for starting LTI authentication. Resets the session and stores a |
||
411 | * reference to this toolbox object in `$_SESSION[Toolbox::class]`. |
||
412 | * |
||
413 | * @link http://stackoverflow.com/a/14329752 StackOverflow discussion |
||
414 | * |
||
415 | * @return void |
||
416 | */ |
||
417 | public function resetSession() |
||
418 | { |
||
419 | /* |
||
420 | * TODO not in love with suppressing errors |
||
421 | */ |
||
422 | if (session_status() !== PHP_SESSION_ACTIVE) { |
||
423 | @session_start(); |
||
0 ignored issues
–
show
|
|||
424 | } |
||
425 | @session_destroy(); |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
426 | @session_unset(); |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
427 | @session_start(); |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
428 | session_regenerate_id(true); |
||
429 | $_SESSION[__CLASS__] =& $this; |
||
430 | session_write_close(); |
||
431 | } |
||
432 | |||
433 | /** |
||
434 | * Update the ToolProvider object |
||
435 | * |
||
436 | * @param ToolProvider $toolProvider |
||
437 | */ |
||
438 | public function setToolProvider(ToolProvider $toolProvider) |
||
439 | { |
||
440 | $this->toolProvider = $toolProvider; |
||
441 | } |
||
442 | |||
443 | /** |
||
444 | * Get the ToolProvider object |
||
445 | * |
||
446 | * This does some just-in-time initialization, so that if the ToolProvider |
||
447 | * has not yet been accessed, it will be instantiated and initialized by this |
||
448 | * method. |
||
449 | * |
||
450 | * @return ToolProvider |
||
451 | */ |
||
452 | public function getToolProvider() |
||
453 | { |
||
454 | if (empty($this->toolProvider)) { |
||
455 | $this->setToolProvider( |
||
456 | new ToolProvider( |
||
457 | $this->mysql, |
||
458 | $this->metadata['TOOL_HANDLER_URLS'] |
||
459 | ) |
||
460 | ); |
||
461 | } |
||
462 | return $this->toolProvider; |
||
463 | } |
||
464 | |||
465 | /** |
||
466 | * Authenticate an LTI launch request |
||
467 | * |
||
468 | * @return void |
||
469 | * @codingStandardsIgnoreStart |
||
470 | */ |
||
471 | public function lti_authenticate() |
||
472 | { |
||
473 | /* @codingStandardsIgnoreEnd */ |
||
474 | $this->getToolProvider()->handle_request(); |
||
475 | } |
||
476 | |||
477 | /** |
||
478 | * Are we (or should we be) in the midst of authenticating an LTI launch request? |
||
479 | * |
||
480 | * @return boolean |
||
481 | * @codingStandardsIgnoreStart |
||
482 | */ |
||
483 | public function lti_isLaunching() |
||
484 | { |
||
485 | /* @codingStandardsIgnoreEnd */ |
||
486 | return !empty($_POST['lti_message_type']); |
||
487 | } |
||
488 | |||
489 | /** |
||
490 | * Create a new Tool consumer |
||
491 | * |
||
492 | * @see ToolProvider::createConsumer() Pass-through to `ToolProvider::createConsumer()` |
||
493 | * |
||
494 | * @param string $name Human-readable name |
||
495 | * @param string $key (Optional) Consumer key (unique within the tool provider) |
||
496 | * @param string $secret (Optional) Shared secret |
||
497 | * @return boolean Whether or not the consumer was created |
||
498 | * @codingStandardsIgnoreStart |
||
499 | */ |
||
500 | public function lti_createConsumer($name, $key = false, $secret = false) |
||
501 | { |
||
502 | /* @codingStandardsIgnoreEnd */ |
||
503 | if ($this->getToolProvider()->createConsumer($name, $key, $secret)) { |
||
504 | $this->log("Created consumer $name"); |
||
505 | return true; |
||
506 | } else { |
||
507 | $this->log("Could not recreate consumer '$name', consumer already exists"); |
||
508 | return false; |
||
509 | } |
||
510 | } |
||
511 | |||
512 | /** |
||
513 | * Get the list of consumers for this tool |
||
514 | * |
||
515 | * @see ToolProvider::getConsumers() Pass-through to `ToolProvider::getConsumers()` |
||
516 | * |
||
517 | * @return LTI_Consumer[] |
||
518 | * @codingStandardsIgnoreStart |
||
519 | */ |
||
520 | public function lti_getConsumers() |
||
521 | { |
||
522 | /* @codingStandardsIgnoreEnd */ |
||
523 | return $this->getToolProvider()->getConsumers(); |
||
524 | } |
||
525 | |||
526 | /** |
||
527 | * Update the API interaction object |
||
528 | * |
||
529 | * @param CanvasPest $api |
||
530 | */ |
||
531 | public function setAPI(CanvasPest $api) |
||
532 | { |
||
533 | $this->api = $api; |
||
534 | } |
||
535 | |||
536 | /** |
||
537 | * Get the API interaction object |
||
538 | |||
539 | * @return CanvasPest |
||
540 | */ |
||
541 | public function getAPI() |
||
542 | { |
||
543 | if (empty($this->api)) { |
||
544 | if (!empty($this->config(static::TOOL_CANVAS_API)['token'])) { |
||
545 | $this->setAPI(new CanvasPest( |
||
546 | 'https://' . $_SESSION[ToolProvider::class]['canvas']['api_domain'] . '/api/v1', |
||
547 | $this->config(static::TOOL_CANVAS_API)['token'] |
||
548 | )); |
||
549 | } else { |
||
550 | throw new ConfigurationException( |
||
551 | 'Canvas URL and Token required', |
||
552 | ConfigurationException::CANVAS_API_INCORRECT |
||
553 | ); |
||
554 | } |
||
555 | } |
||
556 | return $this->api; |
||
557 | } |
||
558 | |||
559 | /** |
||
560 | * Make a GET request to the API |
||
561 | * |
||
562 | * @codingStandardsIgnoreStart |
||
563 | * @link https://htmlpreview.github.io/?https://raw.githubusercontent.com/smtech/canvaspest/master/doc/classes/smtech.CanvasPest.CanvasPest.html#method_get Pass-through to CanvasPest::get() |
||
564 | * @codingStandardsIgnoreEnd |
||
565 | * |
||
566 | * @param string $url |
||
567 | * @param string[] $data (Optional) |
||
568 | * @param string[] $headers (Optional) |
||
569 | * @return \smtech\CanvasPest\CanvasObject|\smtech\CanvasPest\CanvasArray |
||
570 | * @codingStandardsIgnoreStart |
||
571 | */ |
||
572 | public function api_get($url, $data = [], $headers = []) |
||
573 | { |
||
574 | /* @codingStandardsIgnoreEnd */ |
||
575 | return $this->getAPI()->get($url, $data, $headers); |
||
576 | } |
||
577 | |||
578 | /** |
||
579 | * Make a POST request to the API |
||
580 | * |
||
581 | * @codingStandardsIgnoreStart |
||
582 | * @link https://htmlpreview.github.io/?https://raw.githubusercontent.com/smtech/canvaspest/master/doc/classes/smtech.CanvasPest.CanvasPest.html#method_post Pass-through to CanvasPest::post() |
||
583 | * @codingStandardsIgnoreEnd |
||
584 | * |
||
585 | * @param string $url |
||
586 | * @param string[] $data (Optional) |
||
587 | * @param string[] $headers (Optional) |
||
588 | * @return \smtech\CanvasPest\CanvasObject|\smtech\CanvasPest\CanvasArray |
||
589 | * @codingStandardsIgnoreStart |
||
590 | */ |
||
591 | public function api_post($url, $data = [], $headers = []) |
||
592 | { |
||
593 | /* @codingStandardsIgnoreEnd */ |
||
594 | return $this->getAPI()->post($url, $data, $headers); |
||
595 | } |
||
596 | |||
597 | /** |
||
598 | * Make a PUT request to the API |
||
599 | * |
||
600 | * @codingStandardsIgnoreStart |
||
601 | * @link https://htmlpreview.github.io/?https://raw.githubusercontent.com/smtech/canvaspest/master/doc/classes/smtech.CanvasPest.CanvasPest.html#method_put Pass-through to CanvasPest::put() |
||
602 | * @codingStandardsIgnoreEnd |
||
603 | * |
||
604 | * @param string $url |
||
605 | * @param string[] $data (Optional) |
||
606 | * @param string[] $headers (Optional) |
||
607 | * @return \smtech\CanvasPest\CanvasObject|\smtech\CanvasPest\CanvasArray |
||
608 | * @codingStandardsIgnoreStart |
||
609 | */ |
||
610 | public function api_put($url, $data = [], $headers = []) |
||
611 | { |
||
612 | /* @codingStandardsIgnoreEnd */ |
||
613 | return $this->getAPI()->put($url, $data, $headers); |
||
614 | } |
||
615 | |||
616 | /** |
||
617 | * Make a DELETE request to the API |
||
618 | * |
||
619 | * @codingStandardsIgnoreStart |
||
620 | * @link https://htmlpreview.github.io/?https://raw.githubusercontent.com/smtech/canvaspest/master/doc/classes/smtech.CanvasPest.CanvasPest.html#method_delete Pass-through to CanvasPest::delete() |
||
621 | * @codingStandardsIgnoreEnd |
||
622 | * |
||
623 | * @param string $url |
||
624 | * @param string[] $data (Optional) |
||
625 | * @param string[] $headers (Optional) |
||
626 | * @return \smtech\CanvasPest\CanvasObject|\smtech\CanvasPest\CanvasArray |
||
627 | * @codingStandardsIgnoreStart |
||
628 | */ |
||
629 | public function api_delete($url, $data = [], $headers = []) |
||
630 | { |
||
631 | /* @codingStandardsIgnoreEnd */ |
||
632 | return $this->getAPI()->delete($url, $data, $headers); |
||
633 | } |
||
634 | |||
635 | /** |
||
636 | * Set MySQL connection object |
||
637 | * |
||
638 | * @param mysqli $mysql |
||
639 | */ |
||
640 | public function setMySQL(mysqli $mysql) |
||
641 | { |
||
642 | $this->mysql = $mysql; |
||
643 | } |
||
644 | |||
645 | /** |
||
646 | * Get MySQL connection object |
||
647 | * |
||
648 | * @return mysqli |
||
649 | */ |
||
650 | public function getMySQL() |
||
651 | { |
||
652 | return $this->mysql; |
||
653 | } |
||
654 | |||
655 | /** |
||
656 | * Make a MySQL query |
||
657 | * |
||
658 | * @link http://php.net/manual/en/mysqli.query.php Pass-through to `mysqli::query()` |
||
659 | * @param string $query |
||
660 | * @param int $resultMode (Optional, defaults to `MYSQLI_STORE_RESULT`) |
||
661 | * @return mixed |
||
662 | * @codingStandardsIgnoreStart |
||
663 | */ |
||
664 | public function mysql_query($query, $resultMode = MYSQLI_STORE_RESULT) |
||
665 | { |
||
666 | /* @codingStandardsIgnoreEnd */ |
||
667 | return $this->getMySQL()->query($query, $resultMode); |
||
668 | } |
||
669 | |||
670 | /** |
||
671 | * Check if the logger object is ready for use |
||
672 | * @return boolean `TRUE` if ready, `FALSE` otherwise |
||
673 | */ |
||
674 | protected function logReady() |
||
675 | { |
||
676 | return is_a($this->logger, Log::class); |
||
677 | } |
||
678 | |||
679 | /** |
||
680 | * Set log file manager |
||
681 | * |
||
682 | * @param Log $log |
||
683 | */ |
||
684 | public function setLog(Log $log) |
||
685 | { |
||
686 | $this->logger = $log; |
||
687 | } |
||
688 | |||
689 | /** |
||
690 | * Get log file manager |
||
691 | * |
||
692 | * @return Log |
||
693 | */ |
||
694 | public function getLog() |
||
695 | { |
||
696 | return $this->logger; |
||
697 | } |
||
698 | |||
699 | /** |
||
700 | * Queue a message for delayed logging |
||
701 | * @param string $message |
||
702 | * @param string $priority |
||
703 | * @return void |
||
704 | */ |
||
705 | protected function queueLog($message, $priority = null) |
||
706 | { |
||
707 | $this->logQueue[] = ['message' => $message, 'priority' => $priority]; |
||
708 | } |
||
709 | |||
710 | /** |
||
711 | * Flush the delayed log queue |
||
712 | * @return void |
||
713 | */ |
||
714 | protected function flushLogQueue() |
||
715 | { |
||
716 | if ($this->logReady() && !empty($this->logQueue)) { |
||
717 | foreach ($this->logQueue as $entry) { |
||
718 | $this->getLog()->log($entry['message'], $entry['priority']); |
||
719 | } |
||
720 | $this->logQueue = []; |
||
721 | } |
||
722 | } |
||
723 | |||
724 | /** |
||
725 | * Add a message to the tool log file |
||
726 | * |
||
727 | * If no logger object is ready, the message will be queued for delayed |
||
728 | * logging until a logger object is ready. |
||
729 | * |
||
730 | * @link https://pear.php.net/package/Log/docs/1.13.1/Log/Log_file.html#methodlog |
||
731 | * Pass-throgh to `Log_file::log()` |
||
732 | * |
||
733 | * @param string $message |
||
734 | * @param string $priority (Optional, defaults to `PEAR_LOG_INFO`) |
||
735 | * @return boolean Success |
||
736 | */ |
||
737 | public function log($message, $priority = null) |
||
738 | { |
||
739 | if ($this->logReady()) { |
||
740 | $this->flushLogQueue(); |
||
741 | return $this->getLog()->log($message, $priority); |
||
742 | } else { |
||
743 | $this->queueLog($message, $priority); |
||
744 | } |
||
745 | } |
||
746 | |||
747 | /** |
||
748 | * Set the LTI Configuration generator |
||
749 | * |
||
750 | * @param Generator $generator |
||
751 | */ |
||
752 | public function setGenerator(Generator $generator) |
||
753 | { |
||
754 | $this->generator = $generator; |
||
755 | } |
||
756 | |||
757 | /** |
||
758 | * Get the LTI Configuration generator |
||
759 | * |
||
760 | * @return Generator |
||
761 | */ |
||
762 | public function getGenerator() |
||
763 | { |
||
764 | try { |
||
765 | if (empty($this->generator)) { |
||
766 | $this->setGenerator( |
||
767 | new Generator( |
||
768 | $this->config(static::TOOL_NAME), |
||
769 | $this->config(static::TOOL_ID), |
||
770 | $this->config(static::TOOL_LAUNCH_URL), |
||
771 | (empty($this->config(static::TOOL_DESCRIPTION)) ? |
||
772 | false : $this->config(static::TOOL_DESCRIPTION)), |
||
773 | (empty($this->config(static::TOOL_ICON_URL)) ? |
||
774 | false : $this->config(static::TOOL_ICON_URL)), |
||
775 | (empty($this->config(static::TOOL_LAUNCH_PRIVACY)) ? |
||
776 | LaunchPrivacy::USER_PROFILE() : $this->config(static::TOOL_LAUNCH_PRIVACY)), |
||
777 | (empty($this->config(static::TOOL_DOMAIN)) ? false : $this->config(static::TOOL_DOMAIN)) |
||
778 | ) |
||
779 | ); |
||
780 | } |
||
781 | } catch (LTIConfigGeneratorException $e) { |
||
782 | throw new ConfigurationException( |
||
783 | $e->getMessage(), |
||
784 | ConfigurationException::TOOL_PROVIDER |
||
785 | ); |
||
786 | } |
||
787 | return $this->generator; |
||
788 | } |
||
789 | |||
790 | /** |
||
791 | * Get the LTI configuration XML |
||
792 | * |
||
793 | * @codingStandardsIgnoreStart |
||
794 | * @link https://htmlpreview.github.io/?https://raw.githubusercontent.com/smtech/lti-configuration-xml/master/doc/classes/smtech.LTI.Configuration.Generator.html#method_saveXML Pass-through to `Generator::saveXML()` |
||
795 | * @codingStandardsIgnoreEnd |
||
796 | * |
||
797 | * @return string |
||
798 | */ |
||
799 | public function saveConfigurationXML() |
||
800 | { |
||
801 | try { |
||
802 | return $this->getGenerator()->saveXML(); |
||
803 | } catch (LTIConfigGeneratorException $e) { |
||
804 | throw new ConfigurationException( |
||
805 | $e->getMessage(), |
||
806 | ConfigurationException::TOOL_PROVIDER |
||
807 | ); |
||
808 | } |
||
809 | } |
||
810 | } |
||
811 |
If you suppress an error, we recommend checking for the error condition explicitly: