Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/mod/lti/locallib.php
Go to the documentation of this file.
00001 <?php
00002 // This file is part of Moodle - http://moodle.org/
00003 //
00004 // Moodle is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU General Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // Moodle is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00016 //
00017 // This file is part of BasicLTI4Moodle
00018 //
00019 // BasicLTI4Moodle is an IMS BasicLTI (Basic Learning Tools for Interoperability)
00020 // consumer for Moodle 1.9 and Moodle 2.0. BasicLTI is a IMS Standard that allows web
00021 // based learning tools to be easily integrated in LMS as native ones. The IMS BasicLTI
00022 // specification is part of the IMS standard Common Cartridge 1.1 Sakai and other main LMS
00023 // are already supporting or going to support BasicLTI. This project Implements the consumer
00024 // for Moodle. Moodle is a Free Open source Learning Management System by Martin Dougiamas.
00025 // BasicLTI4Moodle is a project iniciated and leaded by Ludo(Marc Alier) and Jordi Piguillem
00026 // at the GESSI research group at UPC.
00027 // SimpleLTI consumer for Moodle is an implementation of the early specification of LTI
00028 // by Charles Severance (Dr Chuck) htp://dr-chuck.com , developed by Jordi Piguillem in a
00029 // Google Summer of Code 2008 project co-mentored by Charles Severance and Marc Alier.
00030 //
00031 // BasicLTI4Moodle is copyright 2009 by Marc Alier Forment, Jordi Piguillem and Nikolas Galanis
00032 // of the Universitat Politecnica de Catalunya http://www.upc.edu
00033 // Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu
00034 
00050 defined('MOODLE_INTERNAL') || die;
00051 
00052 // TODO: Switch to core oauthlib once implemented - MDL-30149
00053 use moodle\mod\lti as lti;
00054 
00055 require_once($CFG->dirroot.'/mod/lti/OAuth.php');
00056 
00057 define('LTI_URL_DOMAIN_REGEX', '/(?:https?:\/\/)?(?:www\.)?([^\/]+)(?:\/|$)/i');
00058 
00059 define('LTI_LAUNCH_CONTAINER_DEFAULT', 1);
00060 define('LTI_LAUNCH_CONTAINER_EMBED', 2);
00061 define('LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS', 3);
00062 define('LTI_LAUNCH_CONTAINER_WINDOW', 4);
00063 define('LTI_LAUNCH_CONTAINER_REPLACE_MOODLE_WINDOW', 5);
00064 
00065 define('LTI_TOOL_STATE_ANY', 0);
00066 define('LTI_TOOL_STATE_CONFIGURED', 1);
00067 define('LTI_TOOL_STATE_PENDING', 2);
00068 define('LTI_TOOL_STATE_REJECTED', 3);
00069 
00070 define('LTI_SETTING_NEVER', 0);
00071 define('LTI_SETTING_ALWAYS', 1);
00072 define('LTI_SETTING_DELEGATE', 2);
00073 
00079 function lti_view($instance) {
00080     global $PAGE, $CFG;
00081 
00082     if (empty($instance->typeid)) {
00083         $tool = lti_get_tool_by_url_match($instance->toolurl, $instance->course);
00084         if ($tool) {
00085             $typeid = $tool->id;
00086         } else {
00087             $typeid = null;
00088         }
00089     } else {
00090         $typeid = $instance->typeid;
00091     }
00092 
00093     if ($typeid) {
00094         $typeconfig = lti_get_type_config($typeid);
00095     } else {
00096         //There is no admin configuration for this tool. Use configuration in the lti instance record plus some defaults.
00097         $typeconfig = (array)$instance;
00098 
00099         $typeconfig['sendname'] = $instance->instructorchoicesendname;
00100         $typeconfig['sendemailaddr'] = $instance->instructorchoicesendemailaddr;
00101         $typeconfig['customparameters'] = $instance->instructorcustomparameters;
00102         $typeconfig['acceptgrades'] = $instance->instructorchoiceacceptgrades;
00103         $typeconfig['allowroster'] = $instance->instructorchoiceallowroster;
00104         $typeconfig['forcessl'] = '0';
00105     }
00106 
00107     //Default the organizationid if not specified
00108     if (empty($typeconfig['organizationid'])) {
00109         $urlparts = parse_url($CFG->wwwroot);
00110 
00111         $typeconfig['organizationid'] = $urlparts['host'];
00112     }
00113 
00114     if (!empty($instance->resourcekey)) {
00115         $key = $instance->resourcekey;
00116     } else if (!empty($typeconfig['resourcekey'])) {
00117         $key = $typeconfig['resourcekey'];
00118     } else {
00119         $key = '';
00120     }
00121 
00122     if (!empty($instance->password)) {
00123         $secret = $instance->password;
00124     } else if (!empty($typeconfig['password'])) {
00125         $secret = $typeconfig['password'];
00126     } else {
00127         $secret = '';
00128     }
00129 
00130     $endpoint = !empty($instance->toolurl) ? $instance->toolurl : $typeconfig['toolurl'];
00131     $endpoint = trim($endpoint);
00132 
00133     //If the current request is using SSL and a secure tool URL is specified, use it
00134     if (lti_request_is_using_ssl() && !empty($instance->securetoolurl)) {
00135         $endpoint = trim($instance->securetoolurl);
00136     }
00137 
00138     //If SSL is forced, use the secure tool url if specified. Otherwise, make sure https is on the normal launch URL.
00139     if ($typeconfig['forcessl'] == '1') {
00140         if (!empty($instance->securetoolurl)) {
00141             $endpoint = trim($instance->securetoolurl);
00142         }
00143 
00144         $endpoint = lti_ensure_url_is_https($endpoint);
00145     } else {
00146         if (!strstr($endpoint, '://')) {
00147             $endpoint = 'http://' . $endpoint;
00148         }
00149     }
00150 
00151     $orgid = $typeconfig['organizationid'];
00152 
00153     $course = $PAGE->course;
00154     $requestparams = lti_build_request($instance, $typeconfig, $course);
00155 
00156     $launchcontainer = lti_get_launch_container($instance, $typeconfig);
00157     $returnurlparams = array('course' => $course->id, 'launch_container' => $launchcontainer, 'instanceid' => $instance->id);
00158 
00159     if ( $orgid ) {
00160         $requestparams["tool_consumer_instance_guid"] = $orgid;
00161     }
00162 
00163     if (empty($key) || empty($secret)) {
00164         $returnurlparams['unsigned'] = '1';
00165 
00166         //Add the return URL. We send the launch container along to help us avoid frames-within-frames when the user returns
00167         $url = new moodle_url('/mod/lti/return.php', $returnurlparams);
00168         $returnurl = $url->out(false);
00169 
00170         if ($typeconfig['forcessl'] == '1') {
00171             $returnurl = lti_ensure_url_is_https($returnurl);
00172         }
00173 
00174         $requestparams['launch_presentation_return_url'] = $returnurl;
00175     }
00176 
00177     if (!empty($key) && !empty($secret)) {
00178         $parms = lti_sign_parameters($requestparams, $endpoint, "POST", $key, $secret);
00179     } else {
00180         //If no key and secret, do the launch unsigned.
00181         $parms = $requestparams;
00182     }
00183 
00184     $debuglaunch = ( $instance->debuglaunch == 1 );
00185 
00186     $content = lti_post_launch_html($parms, $endpoint, $debuglaunch);
00187 
00188     echo $content;
00189 }
00190 
00191 function lti_build_sourcedid($instanceid, $userid, $launchid = null, $servicesalt) {
00192     $data = new stdClass();
00193 
00194     $data->instanceid = $instanceid;
00195     $data->userid = $userid;
00196     if (!empty($launchid)) {
00197         $data->launchid = $launchid;
00198     } else {
00199         $data->launchid = mt_rand();
00200     }
00201 
00202     $json = json_encode($data);
00203 
00204     $hash = hash('sha256', $json . $servicesalt, false);
00205 
00206     $container = new stdClass();
00207     $container->data = $data;
00208     $container->hash = $hash;
00209 
00210     return $container;
00211 }
00212 
00222 function lti_build_request($instance, $typeconfig, $course) {
00223     global $USER, $CFG;
00224 
00225     if (empty($instance->cmid)) {
00226         $instance->cmid = 0;
00227     }
00228 
00229     $role = lti_get_ims_role($USER, $instance->cmid, $instance->course);
00230 
00231     $locale = $course->lang;
00232     if ( strlen($locale) < 1 ) {
00233          $locale = $CFG->lang;
00234     }
00235 
00236     $requestparams = array(
00237         'resource_link_id' => $instance->id,
00238         'resource_link_title' => $instance->name,
00239         'resource_link_description' => $instance->intro,
00240         'user_id' => $USER->id,
00241         'roles' => $role,
00242         'context_id' => $course->id,
00243         'context_label' => $course->shortname,
00244         'context_title' => $course->fullname,
00245         'launch_presentation_locale' => $locale,
00246     );
00247 
00248     $placementsecret = $instance->servicesalt;
00249 
00250     if ( isset($placementsecret) ) {
00251         $sourcedid = json_encode(lti_build_sourcedid($instance->id, $USER->id, null, $placementsecret));
00252     }
00253 
00254     if ( isset($placementsecret) &&
00255          ( $typeconfig['acceptgrades'] == LTI_SETTING_ALWAYS ||
00256          ( $typeconfig['acceptgrades'] == LTI_SETTING_DELEGATE && $instance->instructorchoiceacceptgrades == LTI_SETTING_ALWAYS ) ) ) {
00257         $requestparams['lis_result_sourcedid'] = $sourcedid;
00258 
00259         //Add outcome service URL
00260         $serviceurl = new moodle_url('/mod/lti/service.php');
00261         $serviceurl = $serviceurl->out();
00262 
00263         if ($typeconfig['forcessl'] == '1') {
00264             $serviceurl = lti_ensure_url_is_https($serviceurl);
00265         }
00266 
00267         $requestparams['lis_outcome_service_url'] = $serviceurl;
00268     }
00269 
00270     // Send user's name and email data if appropriate
00271     if ( $typeconfig['sendname'] == LTI_SETTING_ALWAYS ||
00272          ( $typeconfig['sendname'] == LTI_SETTING_DELEGATE && $instance->instructorchoicesendname == LTI_SETTING_ALWAYS ) ) {
00273         $requestparams['lis_person_name_given'] =  $USER->firstname;
00274         $requestparams['lis_person_name_family'] =  $USER->lastname;
00275         $requestparams['lis_person_name_full'] =  $USER->firstname." ".$USER->lastname;
00276     }
00277 
00278     if ( $typeconfig['sendemailaddr'] == LTI_SETTING_ALWAYS ||
00279          ( $typeconfig['sendemailaddr'] == LTI_SETTING_DELEGATE && $instance->instructorchoicesendemailaddr == LTI_SETTING_ALWAYS ) ) {
00280         $requestparams['lis_person_contact_email_primary'] = $USER->email;
00281     }
00282 
00283     // Concatenate the custom parameters from the administrator and the instructor
00284     // Instructor parameters are only taken into consideration if the administrator
00285     // has giver permission
00286     $customstr = $typeconfig['customparameters'];
00287     $instructorcustomstr = $instance->instructorcustomparameters;
00288     $custom = array();
00289     $instructorcustom = array();
00290     if ($customstr) {
00291         $custom = lti_split_custom_parameters($customstr);
00292     }
00293     if (!isset($typeconfig['allowinstructorcustom']) || $typeconfig['allowinstructorcustom'] == LTI_SETTING_NEVER) {
00294         $requestparams = array_merge($custom, $requestparams);
00295     } else {
00296         if ($instructorcustomstr) {
00297             $instructorcustom = lti_split_custom_parameters($instructorcustomstr);
00298         }
00299         foreach ($instructorcustom as $key => $val) {
00300             // Ignore the instructor's parameter
00301             if (!array_key_exists($key, $custom)) {
00302                 $custom[$key] = $val;
00303             }
00304         }
00305         $requestparams = array_merge($custom, $requestparams);
00306     }
00307 
00308     // Make sure we let the tool know what LMS they are being called from
00309     $requestparams["ext_lms"] = "moodle-2";
00310     $requestparams['tool_consumer_info_product_family_code'] = 'moodle';
00311     $requestparams['tool_consumer_info_version'] = strval($CFG->version);
00312 
00313     // Add oauth_callback to be compliant with the 1.0A spec
00314     $requestparams['oauth_callback'] = 'about:blank';
00315 
00316     //The submit button needs to be part of the signature as it gets posted with the form.
00317     //This needs to be here to support launching without javascript.
00318     $submittext = get_string('press_to_submit', 'lti');
00319     $requestparams['ext_submit'] = $submittext;
00320 
00321     $requestparams['lti_version'] = 'LTI-1p0';
00322     $requestparams['lti_message_type'] = 'basic-lti-launch-request';
00323 
00324     return $requestparams;
00325 }
00326 
00327 function lti_get_tool_table($tools, $id) {
00328     global $CFG, $USER;
00329     $html = '';
00330 
00331     $typename = get_string('typename', 'lti');
00332     $baseurl = get_string('baseurl', 'lti');
00333     $action = get_string('action', 'lti');
00334     $createdon = get_string('createdon', 'lti');
00335 
00336     if ($id == 'lti_configured') {
00337         $html .= '<div><a style="margin-top:.25em" href="'.$CFG->wwwroot.'/mod/lti/typessettings.php?action=add&amp;sesskey='.$USER->sesskey.'">'.get_string('addtype', 'lti').'</a></div>';
00338     }
00339 
00340     if (!empty($tools)) {
00341         $html .= "
00342         <div id=\"{$id}_container\" style=\"margin-top:.5em;margin-bottom:.5em\">
00343             <table id=\"{$id}_tools\">
00344                 <thead>
00345                     <tr>
00346                         <th>$typename</th>
00347                         <th>$baseurl</th>
00348                         <th>$createdon</th>
00349                         <th>$action</th>
00350                     </tr>
00351                 </thead>
00352         ";
00353 
00354         foreach ($tools as $type) {
00355             $date = userdate($type->timecreated);
00356             $accept = get_string('accept', 'lti');
00357             $update = get_string('update', 'lti');
00358             $delete = get_string('delete', 'lti');
00359 
00360             $accepthtml = "
00361                 <a class=\"editing_accept\" href=\"{$CFG->wwwroot}/mod/lti/typessettings.php?action=accept&amp;id={$type->id}&amp;sesskey={$USER->sesskey}&amp;tab={$id}\" title=\"{$accept}\">
00362                     <img class=\"iconsmall\" alt=\"{$accept}\" src=\"{$CFG->wwwroot}/pix/t/clear.gif\"/>
00363                 </a>
00364             ";
00365 
00366             $deleteaction = 'delete';
00367 
00368             if ($type->state == LTI_TOOL_STATE_CONFIGURED) {
00369                 $accepthtml = '';
00370             }
00371 
00372             if ($type->state != LTI_TOOL_STATE_REJECTED) {
00373                 $deleteaction = 'reject';
00374                 $delete = get_string('reject', 'lti');
00375             }
00376 
00377             $html .= "
00378             <tr>
00379                 <td>
00380                     {$type->name}
00381                 </td>
00382                 <td>
00383                     {$type->baseurl}
00384                 </td>
00385                 <td>
00386                     {$date}
00387                 </td>
00388                 <td align=\"center\">
00389                     {$accepthtml}
00390                     <a class=\"editing_update\" href=\"{$CFG->wwwroot}/mod/lti/typessettings.php?action=update&amp;id={$type->id}&amp;sesskey={$USER->sesskey}&amp;tab={$id}\" title=\"{$update}\">
00391                         <img class=\"iconsmall\" alt=\"{$update}\" src=\"{$CFG->wwwroot}/pix/t/edit.gif\"/>
00392                     </a>
00393                     <a class=\"editing_delete\" href=\"{$CFG->wwwroot}/mod/lti/typessettings.php?action={$deleteaction}&amp;id={$type->id}&amp;sesskey={$USER->sesskey}&amp;tab={$id}\" title=\"{$delete}\">
00394                         <img class=\"iconsmall\" alt=\"{$delete}\" src=\"{$CFG->wwwroot}/pix/t/delete.gif\"/>
00395                     </a>
00396                 </td>
00397             </tr>
00398             ";
00399         }
00400         $html .= '</table></div>';
00401     } else {
00402         $html .= get_string('no_' . $id, 'lti');
00403     }
00404 
00405     return $html;
00406 }
00407 
00415 function lti_split_custom_parameters($customstr) {
00416     $textlib = textlib_get_instance();
00417 
00418     $lines = preg_split("/[\n;]/", $customstr);
00419     $retval = array();
00420     foreach ($lines as $line) {
00421         $pos = strpos($line, "=");
00422         if ( $pos === false || $pos < 1 ) {
00423             continue;
00424         }
00425         $key = trim($textlib->substr($line, 0, $pos));
00426         $val = trim($textlib->substr($line, $pos+1, strlen($line)));
00427         $key = lti_map_keyname($key);
00428         $retval['custom_'.$key] = $val;
00429     }
00430     return $retval;
00431 }
00432 
00440 function lti_map_keyname($key) {
00441     $textlib = textlib_get_instance();
00442 
00443     $newkey = "";
00444     $key = $textlib->strtolower(trim($key));
00445     foreach (str_split($key) as $ch) {
00446         if ( ($ch >= 'a' && $ch <= 'z') || ($ch >= '0' && $ch <= '9') ) {
00447             $newkey .= $ch;
00448         } else {
00449             $newkey .= '_';
00450         }
00451     }
00452     return $newkey;
00453 }
00454 
00462 function lti_get_ims_role($user, $cmid, $courseid) {
00463     $roles = array();
00464 
00465     if (empty($cmid)) {
00466         //If no cmid is passed, check if the user is a teacher in the course
00467         //This allows other modules to programmatically "fake" a launch without
00468         //a real LTI instance
00469         $coursecontext = get_context_instance(CONTEXT_COURSE, $courseid);
00470 
00471         if (has_capability('moodle/course:manageactivities', $coursecontext)) {
00472             array_push($roles, 'Instructor');
00473         } else {
00474             array_push($roles, 'Learner');
00475         }
00476     } else {
00477         $context = get_context_instance(CONTEXT_MODULE, $cmid);
00478 
00479         if (has_capability('mod/lti:manage', $context)) {
00480             array_push($roles, 'Instructor');
00481         } else {
00482             array_push($roles, 'Learner');
00483         }
00484     }
00485 
00486     if (is_siteadmin($user)) {
00487         array_push($roles, 'urn:lti:sysrole:ims/lis/Administrator');
00488     }
00489 
00490     return join(',', $roles);
00491 }
00492 
00500 function lti_get_type_config($typeid) {
00501     global $DB;
00502 
00503     $query = "SELECT name, value
00504                 FROM {lti_types_config}
00505                WHERE typeid = :typeid1
00506            UNION ALL
00507               SELECT 'toolurl' AS name, baseurl AS value
00508                 FROM {lti_types}
00509                WHERE id = :typeid2";
00510 
00511     $typeconfig = array();
00512     $configs = $DB->get_records_sql($query, array('typeid1' => $typeid, 'typeid2' => $typeid));
00513 
00514     if (!empty($configs)) {
00515         foreach ($configs as $config) {
00516             $typeconfig[$config->name] = $config->value;
00517         }
00518     }
00519 
00520     return $typeconfig;
00521 }
00522 
00523 function lti_get_tools_by_url($url, $state, $courseid = null) {
00524     $domain = lti_get_domain_from_url($url);
00525 
00526     return lti_get_tools_by_domain($domain, $state, $courseid);
00527 }
00528 
00529 function lti_get_tools_by_domain($domain, $state = null, $courseid = null) {
00530     global $DB, $SITE;
00531 
00532     $filters = array('tooldomain' => $domain);
00533 
00534     $statefilter = '';
00535     $coursefilter = '';
00536 
00537     if ($state) {
00538         $statefilter = 'AND state = :state';
00539     }
00540 
00541     if ($courseid && $courseid != $SITE->id) {
00542         $coursefilter = 'OR course = :courseid';
00543     }
00544 
00545     $query = "SELECT *
00546                 FROM {lti_types}
00547                WHERE tooldomain = :tooldomain
00548                  AND (course = :siteid $coursefilter)
00549                  $statefilter";
00550 
00551     return $DB->get_records_sql($query, array(
00552         'courseid' => $courseid,
00553         'siteid' => $SITE->id,
00554         'tooldomain' => $domain,
00555         'state' => $state
00556     ));
00557 }
00558 
00563 function lti_filter_get_types($course) {
00564     global $DB;
00565 
00566     if (!empty($course)) {
00567         $filter = array('course' => $course);
00568     } else {
00569         $filter = array();
00570     }
00571 
00572     return $DB->get_records('lti_types', $filter);
00573 }
00574 
00575 function lti_get_types_for_add_instance() {
00576     global $DB, $SITE, $COURSE;
00577 
00578     $query = "SELECT *
00579                 FROM {lti_types}
00580                WHERE coursevisible = 1
00581                  AND (course = :siteid OR course = :courseid)
00582                  AND state = :active";
00583 
00584     $admintypes = $DB->get_records_sql($query, array('siteid' => $SITE->id, 'courseid' => $COURSE->id, 'active' => LTI_TOOL_STATE_CONFIGURED));
00585 
00586     $types = array();
00587     $types[0] = (object)array('name' => get_string('automatic', 'lti'), 'course' => $SITE->id);
00588 
00589     foreach ($admintypes as $type) {
00590         $types[$type->id] = $type;
00591     }
00592 
00593     return $types;
00594 }
00595 
00596 function lti_get_domain_from_url($url) {
00597     $matches = array();
00598 
00599     if (preg_match(LTI_URL_DOMAIN_REGEX, $url, $matches)) {
00600         return $matches[1];
00601     }
00602 }
00603 
00604 function lti_get_tool_by_url_match($url, $courseid = null, $state = LTI_TOOL_STATE_CONFIGURED) {
00605     $possibletools = lti_get_tools_by_url($url, $state, $courseid);
00606 
00607     return lti_get_best_tool_by_url($url, $possibletools, $courseid);
00608 }
00609 
00610 function lti_get_url_thumbprint($url) {
00611     $urlparts = parse_url(strtolower($url));
00612     if (!isset($urlparts['path'])) {
00613         $urlparts['path'] = '';
00614     }
00615 
00616     if (!isset($urlparts['host'])) {
00617         $urlparts['host'] = '';
00618     }
00619 
00620     if (substr($urlparts['host'], 0, 4) === 'www.') {
00621         $urlparts['host'] = substr($urlparts['host'], 4);
00622     }
00623 
00624     return $urllower = $urlparts['host'] . '/' . $urlparts['path'];
00625 }
00626 
00627 function lti_get_best_tool_by_url($url, $tools, $courseid = null) {
00628     if (count($tools) === 0) {
00629         return null;
00630     }
00631 
00632     $urllower = lti_get_url_thumbprint($url);
00633 
00634     foreach ($tools as $tool) {
00635         $tool->_matchscore = 0;
00636 
00637         $toolbaseurllower = lti_get_url_thumbprint($tool->baseurl);
00638 
00639         if ($urllower === $toolbaseurllower) {
00640             //100 points for exact thumbprint match
00641             $tool->_matchscore += 100;
00642         } else if (substr($urllower, 0, strlen($toolbaseurllower)) === $toolbaseurllower) {
00643             //50 points if tool thumbprint starts with the base URL thumbprint
00644             $tool->_matchscore += 50;
00645         }
00646 
00647         //Prefer course tools over site tools
00648         if (!empty($courseid)) {
00649             //Minus 10 points for not matching the course id (global tools)
00650             if ($tool->course != $courseid) {
00651                 $tool->_matchscore -= 10;
00652             }
00653         }
00654     }
00655 
00656     $bestmatch = array_reduce($tools, function($value, $tool) {
00657         if ($tool->_matchscore > $value->_matchscore) {
00658             return $tool;
00659         } else {
00660             return $value;
00661         }
00662 
00663     }, (object)array('_matchscore' => -1));
00664 
00665     //None of the tools are suitable for this URL
00666     if ($bestmatch->_matchscore <= 0) {
00667         return null;
00668     }
00669 
00670     return $bestmatch;
00671 }
00672 
00673 function lti_get_shared_secrets_by_key($key) {
00674     global $DB;
00675 
00676     //Look up the shared secret for the specified key in both the types_config table (for configured tools)
00677     //And in the lti resource table for ad-hoc tools
00678     $query = "SELECT t2.value
00679                 FROM {lti_types_config} t1
00680                 JOIN {lti_types_config} t2 ON t1.typeid = t2.typeid
00681                 JOIN {lti_types} type ON t2.typeid = type.id
00682               WHERE t1.name = 'resourcekey'
00683                 AND t1.value = :key1
00684                 AND t2.name = 'password'
00685                 AND type.state = :configured
00686               UNION
00687              SELECT password AS value
00688                FROM {lti}
00689               WHERE resourcekey = :key2";
00690 
00691     $sharedsecrets = $DB->get_records_sql($query, array('configured' => LTI_TOOL_STATE_CONFIGURED, 'key1' => $key, 'key2' => $key));
00692 
00693     $values = array_map(function($item) {
00694         return $item->value;
00695     }, $sharedsecrets);
00696 
00697     //There should really only be one shared secret per key. But, we can't prevent
00698     //more than one getting entered. For instance, if the same key is used for two tool providers.
00699     return $values;
00700 }
00701 
00707 function lti_delete_type($id) {
00708     global $DB;
00709 
00710     //We should probably just copy the launch URL to the tool instances in this case... using a single query
00711     /*
00712     $instances = $DB->get_records('lti', array('typeid' => $id));
00713     foreach ($instances as $instance) {
00714         $instance->typeid = 0;
00715         $DB->update_record('lti', $instance);
00716     }*/
00717 
00718     $DB->delete_records('lti_types', array('id' => $id));
00719     $DB->delete_records('lti_types_config', array('typeid' => $id));
00720 }
00721 
00722 function lti_set_state_for_type($id, $state) {
00723     global $DB;
00724 
00725     $DB->update_record('lti_types', array('id' => $id, 'state' => $state));
00726 }
00727 
00735 function lti_get_config($ltiobject) {
00736     $typeconfig = array();
00737     $typeconfig = (array)$ltiobject;
00738     $additionalconfig = lti_get_type_config($ltiobject->typeid);
00739     $typeconfig = array_merge($typeconfig, $additionalconfig);
00740     return $typeconfig;
00741 }
00742 
00752 function lti_get_type_config_from_instance($id) {
00753     global $DB;
00754 
00755     $instance = $DB->get_record('lti', array('id' => $id));
00756     $config = lti_get_config($instance);
00757 
00758     $type = new stdClass();
00759     $type->lti_fix = $id;
00760     if (isset($config['toolurl'])) {
00761         $type->lti_toolurl = $config['toolurl'];
00762     }
00763     if (isset($config['instructorchoicesendname'])) {
00764         $type->lti_sendname = $config['instructorchoicesendname'];
00765     }
00766     if (isset($config['instructorchoicesendemailaddr'])) {
00767         $type->lti_sendemailaddr = $config['instructorchoicesendemailaddr'];
00768     }
00769     if (isset($config['instructorchoiceacceptgrades'])) {
00770         $type->lti_acceptgrades = $config['instructorchoiceacceptgrades'];
00771     }
00772     if (isset($config['instructorchoiceallowroster'])) {
00773         $type->lti_allowroster = $config['instructorchoiceallowroster'];
00774     }
00775 
00776     if (isset($config['instructorcustomparameters'])) {
00777         $type->lti_allowsetting = $config['instructorcustomparameters'];
00778     }
00779     return $type;
00780 }
00781 
00789 function lti_get_type_type_config($id) {
00790     global $DB;
00791 
00792     $basicltitype = $DB->get_record('lti_types', array('id' => $id));
00793     $config = lti_get_type_config($id);
00794 
00795     $type = new stdClass();
00796 
00797     $type->lti_typename = $basicltitype->name;
00798 
00799     $type->typeid = $basicltitype->id;
00800 
00801     $type->lti_toolurl = $basicltitype->baseurl;
00802 
00803     if (isset($config['resourcekey'])) {
00804         $type->lti_resourcekey = $config['resourcekey'];
00805     }
00806     if (isset($config['password'])) {
00807         $type->lti_password = $config['password'];
00808     }
00809 
00810     if (isset($config['sendname'])) {
00811         $type->lti_sendname = $config['sendname'];
00812     }
00813     if (isset($config['instructorchoicesendname'])) {
00814         $type->lti_instructorchoicesendname = $config['instructorchoicesendname'];
00815     }
00816     if (isset($config['sendemailaddr'])) {
00817         $type->lti_sendemailaddr = $config['sendemailaddr'];
00818     }
00819     if (isset($config['instructorchoicesendemailaddr'])) {
00820         $type->lti_instructorchoicesendemailaddr = $config['instructorchoicesendemailaddr'];
00821     }
00822     if (isset($config['acceptgrades'])) {
00823         $type->lti_acceptgrades = $config['acceptgrades'];
00824     }
00825     if (isset($config['instructorchoiceacceptgrades'])) {
00826         $type->lti_instructorchoiceacceptgrades = $config['instructorchoiceacceptgrades'];
00827     }
00828     if (isset($config['allowroster'])) {
00829         $type->lti_allowroster = $config['allowroster'];
00830     }
00831     if (isset($config['instructorchoiceallowroster'])) {
00832         $type->lti_instructorchoiceallowroster = $config['instructorchoiceallowroster'];
00833     }
00834 
00835     if (isset($config['customparameters'])) {
00836         $type->lti_customparameters = $config['customparameters'];
00837     }
00838 
00839     if (isset($config['forcessl'])) {
00840         $type->lti_forcessl = $config['forcessl'];
00841     }
00842 
00843     if (isset($config['organizationid'])) {
00844         $type->lti_organizationid = $config['organizationid'];
00845     }
00846     if (isset($config['organizationurl'])) {
00847         $type->lti_organizationurl = $config['organizationurl'];
00848     }
00849     if (isset($config['organizationdescr'])) {
00850         $type->lti_organizationdescr = $config['organizationdescr'];
00851     }
00852     if (isset($config['launchcontainer'])) {
00853         $type->lti_launchcontainer = $config['launchcontainer'];
00854     }
00855 
00856     if (isset($config['coursevisible'])) {
00857         $type->lti_coursevisible = $config['coursevisible'];
00858     }
00859 
00860     if (isset($config['debuglaunch'])) {
00861         $type->lti_debuglaunch = $config['debuglaunch'];
00862     }
00863 
00864     if (isset($config['module_class_type'])) {
00865         $type->lti_module_class_type = $config['module_class_type'];
00866     }
00867 
00868     return $type;
00869 }
00870 
00871 function lti_prepare_type_for_save($type, $config) {
00872     $type->baseurl = $config->lti_toolurl;
00873     $type->tooldomain = lti_get_domain_from_url($config->lti_toolurl);
00874     $type->name = $config->lti_typename;
00875 
00876     $type->coursevisible = !empty($config->lti_coursevisible) ? $config->lti_coursevisible : 0;
00877     $config->lti_coursevisible = $type->coursevisible;
00878 
00879     $type->forcessl = !empty($config->lti_forcessl) ? $config->lti_forcessl : 0;
00880     $config->lti_forcessl = $type->forcessl;
00881 
00882     $type->timemodified = time();
00883 
00884     unset ($config->lti_typename);
00885     unset ($config->lti_toolurl);
00886 }
00887 
00888 function lti_update_type($type, $config) {
00889     global $DB;
00890 
00891     lti_prepare_type_for_save($type, $config);
00892 
00893     if ($DB->update_record('lti_types', $type)) {
00894         foreach ($config as $key => $value) {
00895             if (substr($key, 0, 4)=='lti_' && !is_null($value)) {
00896                 $record = new StdClass();
00897                 $record->typeid = $type->id;
00898                 $record->name = substr($key, 4);
00899                 $record->value = $value;
00900 
00901                 lti_update_config($record);
00902             }
00903         }
00904     }
00905 }
00906 
00907 function lti_add_type($type, $config) {
00908     global $USER, $SITE, $DB;
00909 
00910     lti_prepare_type_for_save($type, $config);
00911 
00912     if (!isset($type->state)) {
00913         $type->state = LTI_TOOL_STATE_PENDING;
00914     }
00915 
00916     if (!isset($type->timecreated)) {
00917         $type->timecreated = time();
00918     }
00919 
00920     if (!isset($type->createdby)) {
00921         $type->createdby = $USER->id;
00922     }
00923 
00924     if (!isset($type->course)) {
00925         $type->course = $SITE->id;
00926     }
00927 
00928     //Create a salt value to be used for signing passed data to extension services
00929     //The outcome service uses the service salt on the instance. This can be used
00930     //for communication with services not related to a specific LTI instance.
00931     $config->lti_servicesalt = uniqid('', true);
00932 
00933     $id = $DB->insert_record('lti_types', $type);
00934 
00935     if ($id) {
00936         foreach ($config as $key => $value) {
00937             if (substr($key, 0, 4)=='lti_' && !is_null($value)) {
00938                 $record = new StdClass();
00939                 $record->typeid = $id;
00940                 $record->name = substr($key, 4);
00941                 $record->value = $value;
00942 
00943                 lti_add_config($record);
00944             }
00945         }
00946     }
00947 
00948     return $id;
00949 }
00950 
00958 function lti_add_config($config) {
00959     global $DB;
00960 
00961     return $DB->insert_record('lti_types_config', $config);
00962 }
00963 
00971 function lti_update_config($config) {
00972     global $DB;
00973 
00974     $return = true;
00975     $old = $DB->get_record('lti_types_config', array('typeid' => $config->typeid, 'name' => $config->name));
00976 
00977     if ($old) {
00978         $config->id = $old->id;
00979         $return = $DB->update_record('lti_types_config', $config);
00980     } else {
00981         $return = $DB->insert_record('lti_types_config', $config);
00982     }
00983     return $return;
00984 }
00985 
00998 function lti_sign_parameters($oldparms, $endpoint, $method, $oauthconsumerkey, $oauthconsumersecret) {
00999     //global $lastbasestring;
01000     $parms = $oldparms;
01001 
01002     $testtoken = '';
01003 
01004     // TODO: Switch to core oauthlib once implemented - MDL-30149
01005     $hmacmethod = new lti\OAuthSignatureMethod_HMAC_SHA1();
01006     $testconsumer = new lti\OAuthConsumer($oauthconsumerkey, $oauthconsumersecret, null);
01007     $accreq = lti\OAuthRequest::from_consumer_and_token($testconsumer, $testtoken, $method, $endpoint, $parms);
01008     $accreq->sign_request($hmacmethod, $testconsumer, $testtoken);
01009 
01010     // Pass this back up "out of band" for debugging
01011     //$lastbasestring = $accreq->get_signature_base_string();
01012 
01013     $newparms = $accreq->get_parameters();
01014 
01015     return $newparms;
01016 }
01017 
01025 function lti_post_launch_html($newparms, $endpoint, $debug=false) {
01026     $r = "<form action=\"".$endpoint."\" name=\"ltiLaunchForm\" id=\"ltiLaunchForm\" method=\"post\" encType=\"application/x-www-form-urlencoded\">\n";
01027 
01028     $submittext = $newparms['ext_submit'];
01029 
01030     // Contruct html for the launch parameters
01031     foreach ($newparms as $key => $value) {
01032         $key = htmlspecialchars($key);
01033         $value = htmlspecialchars($value);
01034         if ( $key == "ext_submit" ) {
01035             $r .= "<input type=\"submit\" name=\"";
01036         } else {
01037             $r .= "<input type=\"hidden\" name=\"";
01038         }
01039         $r .= $key;
01040         $r .= "\" value=\"";
01041         $r .= $value;
01042         $r .= "\"/>\n";
01043     }
01044 
01045     if ( $debug ) {
01046         $r .= "<script language=\"javascript\"> \n";
01047         $r .= "  //<![CDATA[ \n";
01048         $r .= "function basicltiDebugToggle() {\n";
01049         $r .= "    var ele = document.getElementById(\"basicltiDebug\");\n";
01050         $r .= "    if (ele.style.display == \"block\") {\n";
01051         $r .= "        ele.style.display = \"none\";\n";
01052         $r .= "    }\n";
01053         $r .= "    else {\n";
01054         $r .= "        ele.style.display = \"block\";\n";
01055         $r .= "    }\n";
01056         $r .= "} \n";
01057         $r .= "  //]]> \n";
01058         $r .= "</script>\n";
01059         $r .= "<a id=\"displayText\" href=\"javascript:basicltiDebugToggle();\">";
01060         $r .= get_string("toggle_debug_data", "lti")."</a>\n";
01061         $r .= "<div id=\"basicltiDebug\" style=\"display:none\">\n";
01062         $r .=  "<b>".get_string("basiclti_endpoint", "lti")."</b><br/>\n";
01063         $r .= $endpoint . "<br/>\n&nbsp;<br/>\n";
01064         $r .=  "<b>".get_string("basiclti_parameters", "lti")."</b><br/>\n";
01065         foreach ($newparms as $key => $value) {
01066             $key = htmlspecialchars($key);
01067             $value = htmlspecialchars($value);
01068             $r .= "$key = $value<br/>\n";
01069         }
01070         $r .= "&nbsp;<br/>\n";
01071         //$r .= "<p><b>".get_string("basiclti_base_string", "lti")."</b><br/>\n".$lastbasestring."</p>\n";
01072         $r .= "</div>\n";
01073     }
01074     $r .= "</form>\n";
01075 
01076     if ( ! $debug ) {
01077         $ext_submit = "ext_submit";
01078         $ext_submit_text = $submittext;
01079         $r .= " <script type=\"text/javascript\"> \n" .
01080             "  //<![CDATA[ \n" .
01081             "    document.getElementById(\"ltiLaunchForm\").style.display = \"none\";\n" .
01082             "    nei = document.createElement('input');\n" .
01083             "    nei.setAttribute('type', 'hidden');\n" .
01084             "    nei.setAttribute('name', '".$ext_submit."');\n" .
01085             "    nei.setAttribute('value', '".$ext_submit_text."');\n" .
01086             "    document.getElementById(\"ltiLaunchForm\").appendChild(nei);\n" .
01087             "    document.ltiLaunchForm.submit(); \n" .
01088             "  //]]> \n" .
01089             " </script> \n";
01090     }
01091     return $r;
01092 }
01093 
01094 function lti_get_type($typeid) {
01095     global $DB;
01096 
01097     return $DB->get_record('lti_types', array('id' => $typeid));
01098 }
01099 
01100 function lti_get_launch_container($lti, $toolconfig) {
01101     if (empty($lti->launchcontainer)) {
01102         $lti->launchcontainer = LTI_LAUNCH_CONTAINER_DEFAULT;
01103     }
01104 
01105     if ($lti->launchcontainer == LTI_LAUNCH_CONTAINER_DEFAULT) {
01106         if (isset($toolconfig['launchcontainer'])) {
01107             $launchcontainer = $toolconfig['launchcontainer'];
01108         }
01109     } else {
01110         $launchcontainer = $lti->launchcontainer;
01111     }
01112 
01113     if (empty($launchcontainer) || $launchcontainer == LTI_LAUNCH_CONTAINER_DEFAULT) {
01114         $launchcontainer = LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS;
01115     }
01116 
01117     $devicetype = get_device_type();
01118 
01119     //Scrolling within the object element doesn't work on iOS or Android
01120     //Opening the popup window also had some issues in testing
01121     //For mobile devices, always take up the entire screen to ensure the best experience
01122     if ($devicetype === 'mobile' || $devicetype === 'tablet' ) {
01123         $launchcontainer = LTI_LAUNCH_CONTAINER_REPLACE_MOODLE_WINDOW;
01124     }
01125 
01126     return $launchcontainer;
01127 }
01128 
01129 function lti_request_is_using_ssl() {
01130     global $CFG;
01131     return (stripos($CFG->httpswwwroot, 'https://') === 0);
01132 }
01133 
01134 function lti_ensure_url_is_https($url) {
01135     if (!strstr($url, '://')) {
01136         $url = 'https://' . $url;
01137     } else {
01138         //If the URL starts with http, replace with https
01139         if (stripos($url, 'http://') === 0) {
01140             $url = 'https://' . substr($url, 8);
01141         }
01142     }
01143 
01144     return $url;
01145 }
 All Data Structures Namespaces Files Functions Variables Enumerations