function refresh_key() { global $CFG; // set up an RPC request require_once $CFG->dirroot . '/mnet/xmlrpc/client.php'; $mnetrequest = new mnet_xmlrpc_client(); // Use any method - listServices is pretty lightweight. $mnetrequest->set_method('system/listServices'); // Do RPC call and store response if ($mnetrequest->send($this) === true) { // Ok - we actually don't care about the result $temp = new mnet_peer(); $temp->set_id($this->id); if ($this->public_key != $temp->public_key) { $newkey = clean_param($temp->public_key, PARAM_PEM); if (!empty($newkey)) { $this->public_key = $newkey; $this->updateparams->public_key = $newkey; $this->commit(); return true; } } } return false; }
function refresh_key() { // set up an RPC request $mnetrequest = new mnet_xmlrpc_client(); // Use any method - listServices is pretty lightweight. $mnetrequest->set_method('system/listServices'); // Do RPC call and store response if ($mnetrequest->send($this) === true) { // Ok - we actually don't care about the result $temp = new mnet_peer(); $temp->set_id($this->id); if ($this->public_key != $temp->public_key) { $newkey = param_clean($temp->public_key, PARAM_PEM); if (!empty($newkey)) { $this->public_key = $newkey; return true; } } } return false; }
/** * Work out the theme this page should use. * * This depends on numerous $CFG settings, and the properties of this page. * * @return string the name of the theme that should be used on this page. */ protected function resolve_theme() { global $CFG, $USER, $SESSION; if (empty($CFG->themeorder)) { $themeorder = array('course', 'category', 'session', 'user', 'site'); } else { $themeorder = $CFG->themeorder; // Just in case, make sure we always use the site theme if nothing else matched. $themeorder[] = 'site'; } $mnetpeertheme = ''; if (isloggedin() and isset($CFG->mnet_localhost_id) and $USER->mnethostid != $CFG->mnet_localhost_id) { require_once $CFG->dirroot . '/mnet/peer.php'; $mnetpeer = new mnet_peer(); $mnetpeer->set_id($USER->mnethostid); if ($mnetpeer->force_theme == 1 && $mnetpeer->theme != '') { $mnetpeertheme = $mnetpeer->theme; } } $devicetheme = core_useragent::get_device_type_theme($this->devicetypeinuse); // The user is using another device than default, and we have a theme for that, we should use it. $hascustomdevicetheme = core_useragent::DEVICETYPE_DEFAULT != $this->devicetypeinuse && !empty($devicetheme); foreach ($themeorder as $themetype) { switch ($themetype) { case 'course': if (!empty($CFG->allowcoursethemes) && !empty($this->_course->theme) && !$hascustomdevicetheme) { return $this->_course->theme; } break; case 'category': if (!empty($CFG->allowcategorythemes) && !$hascustomdevicetheme) { $categories = $this->categories; foreach ($categories as $category) { if (!empty($category->theme)) { return $category->theme; } } } break; case 'session': if (!empty($SESSION->theme)) { return $SESSION->theme; } break; case 'user': if (!empty($CFG->allowuserthemes) && !empty($USER->theme) && !$hascustomdevicetheme) { if ($mnetpeertheme) { return $mnetpeertheme; } else { return $USER->theme; } } break; case 'site': if ($mnetpeertheme) { return $mnetpeertheme; } // First try for the device the user is using. if (!empty($devicetheme)) { return $devicetheme; } // Next try for the default device (as a fallback). $devicetheme = core_useragent::get_device_type_theme(core_useragent::DEVICETYPE_DEFAULT); if (!empty($devicetheme)) { return $devicetheme; } // The default device theme isn't set up - use the overall default theme. return theme_config::DEFAULT_THEME; } } // We should most certainly have resolved a theme by now. Something has gone wrong. debugging('Error resolving the theme to use for this page.', DEBUG_DEVELOPER); return theme_config::DEFAULT_THEME; }
/** * Send the request to the server - decode and return the response * * @param object $mnet_peer A mnet_peer object with details of the * remote host we're connecting to * @return mixed A PHP variable, as returned by the * remote function */ function send($mnet_peer) { global $CFG, $MNET; $this->uri = $mnet_peer->wwwroot . $mnet_peer->application->xmlrpc_server_url; // Initialize with the target URL $ch = curl_init($this->uri); $system_methods = array('system/listMethods', 'system/methodSignature', 'system/methodHelp', 'system/listServices'); if (in_array($this->method, $system_methods)) { // Executing any system method is permitted. } else { $id_list = $mnet_peer->id; if (!empty($CFG->mnet_all_hosts_id)) { $id_list .= ', ' . $CFG->mnet_all_hosts_id; } // At this point, we don't care if the remote host implements the // method we're trying to call. We just want to know that: // 1. The method belongs to some service, as far as OUR host knows // 2. We are allowed to subscribe to that service on this mnet_peer // Find methods that we subscribe to on this host $sql = "\n SELECT\n r.id\n FROM\n {$CFG->prefix}mnet_rpc r,\n {$CFG->prefix}mnet_service2rpc s2r,\n {$CFG->prefix}mnet_host2service h2s\n WHERE\n r.xmlrpc_path = '{$this->method}' AND\n s2r.rpcid = r.id AND\n s2r.serviceid = h2s.serviceid AND\n h2s.subscribe = '1' AND\n h2s.hostid in ({$id_list})"; if (!record_exists_sql($sql)) { global $USER; $this->error[] = '7:User with ID ' . $USER->id . ' attempted to call unauthorised method ' . $this->method . ' on host ' . $mnet_peer->wwwroot; return false; } } $this->requesttext = xmlrpc_encode_request($this->method, $this->params, array("encoding" => "utf-8", "escaping" => "markup")); $rq = $this->requesttext; $rq = mnet_sign_message($this->requesttext); $this->signedrequest = $rq; $rq = mnet_encrypt_message($rq, $mnet_peer->public_key); $this->encryptedrequest = $rq; curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Moodle'); curl_setopt($ch, CURLOPT_POSTFIELDS, $rq); curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: text/xml charset=UTF-8")); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); $timestamp_send = time(); $this->rawresponse = curl_exec($ch); $timestamp_receive = time(); if ($this->rawresponse === false) { $this->error[] = curl_errno($ch) . ':' . curl_error($ch); return false; } $this->rawresponse = trim($this->rawresponse); $mnet_peer->touch(); $crypt_parser = new mnet_encxml_parser(); $crypt_parser->parse($this->rawresponse); if ($crypt_parser->payload_encrypted) { $key = array_pop($crypt_parser->cipher); $data = array_pop($crypt_parser->cipher); $crypt_parser->free_resource(); // Initialize payload var $payload = ''; // &$payload $isOpen = openssl_open(base64_decode($data), $payload, base64_decode($key), $MNET->get_private_key()); if (!$isOpen) { // Decryption failed... let's try our archived keys $openssl_history = get_config('mnet', 'openssl_history'); if (empty($openssl_history)) { $openssl_history = array(); set_config('openssl_history', serialize($openssl_history), 'mnet'); } else { $openssl_history = unserialize($openssl_history); } foreach ($openssl_history as $keyset) { $keyresource = openssl_pkey_get_private($keyset['keypair_PEM']); $isOpen = openssl_open(base64_decode($data), $payload, base64_decode($key), $keyresource); if ($isOpen) { // It's an older code, sir, but it checks out break; } } } if (!$isOpen) { trigger_error("None of our keys could open the payload from host {$mnet_peer->wwwroot} with id {$mnet_peer->id}."); $this->error[] = '3:No key match'; return false; } if (strpos(substr($payload, 0, 100), '<signedMessage>')) { $sig_parser = new mnet_encxml_parser(); $sig_parser->parse($payload); } else { $this->error[] = '2:Payload not signed: ' . $payload; return false; } } else { if (!empty($crypt_parser->remoteerror)) { $this->error[] = '4: remote server error: ' . $crypt_parser->remoteerror; } else { if (!empty($crypt_parser->error)) { $crypt_parser_error = $crypt_parser->error[0]; $message = '3:XML Parse error in payload: ' . $crypt_parser_error['string'] . "\n"; if (array_key_exists('lineno', $crypt_parser_error)) { $message .= 'At line number: ' . $crypt_parser_error['lineno'] . "\n"; } if (array_key_exists('line', $crypt_parser_error)) { $message .= 'Which reads: ' . $crypt_parser_error['line'] . "\n"; } $this->error[] = $message; } else { $this->error[] = '1:Payload not encrypted '; } } $crypt_parser->free_resource(); return false; } // Margin of error is the time it took the request to complete. $margin_of_error = $timestamp_receive - $timestamp_send; // Guess the time gap between sending the request and the remote machine // executing the time() function. Marginally better than nothing. $hysteresis = $margin_of_error / 2; $remote_timestamp = $sig_parser->remote_timestamp - $hysteresis; $time_offset = $remote_timestamp - $timestamp_send; if ($time_offset > 0) { $threshold = get_config('mnet', 'drift_threshold'); if (empty($threshold)) { // We decided 15 seconds was a pretty good arbitrary threshold // for time-drift between servers, but you can customize this in // the config_plugins table. It's not advised though. set_config('drift_threshold', 15, 'mnet'); $threshold = 15; } if ($time_offset > $threshold) { $this->error[] = '6:Time gap with ' . $mnet_peer->name . ' (' . $time_offset . ' seconds) is greater than the permitted maximum of ' . $threshold . ' seconds'; return false; } } $this->xmlrpcresponse = base64_decode($sig_parser->data_object); $this->response = xmlrpc_decode($this->xmlrpcresponse); curl_close($ch); // xmlrpc errors are pushed onto the $this->error stack if (is_array($this->response) && array_key_exists('faultCode', $this->response)) { // The faultCode 7025 means we tried to connect with an old SSL key // The faultString is the new key - let's save it and try again // The re_key attribute stops us from getting into a loop if ($this->response['faultCode'] == 7025 && empty($mnet_peer->re_key)) { $record = new stdClass(); $record->id = $mnet_peer->id; if ($this->response['faultString'] == clean_param($this->response['faultString'], PARAM_PEM)) { $record->public_key = $this->response['faultString']; $details = openssl_x509_parse($record->public_key); if (is_array($details) && isset($details['validTo_time_t'])) { $record->public_key_expires = $details['validTo_time_t']; update_record('mnet_host', $record); $mnet_peer2 = new mnet_peer(); $mnet_peer2->set_id($record->id); $mnet_peer2->re_key = true; $this->send($mnet_peer2); } else { $this->error[] = $this->response['faultCode'] . " : " . $this->response['faultString']; } } else { $this->error[] = $this->response['faultCode'] . " : " . $this->response['faultString']; } } else { if (!empty($CFG->mnet_rpcdebug)) { $guidance = get_string('error' . $this->response['faultCode'], 'mnet'); } else { $guidance = ''; } $this->error[] = $this->response['faultCode'] . " : " . $this->response['faultString']; } } // ok, it's signed, but is it signed with the right certificate ? // do this *after* we check for an out of date key $verified = openssl_verify($this->xmlrpcresponse, base64_decode($sig_parser->signature), $mnet_peer->public_key); if ($verified != 1) { $this->error[] = 'Invalid signature'; } return empty($this->error); }
} } if ('input' == $form->step) { include './mnet_review.html'; } elseif ('commit' == $form->step) { $bool = $mnet_peer->commit(); if ($bool) { redirect('peers.php?step=update&hostid=' . $mnet_peer->id, get_string('changessaved')); } else { print_error('invalidaction', 'error', 'index.php'); } } } } elseif (is_int($hostid)) { $mnet_peer = new mnet_peer(); $mnet_peer->set_id($hostid); $currentkey = mnet_get_public_key($mnet_peer->wwwroot, $mnet_peer->application); if ($currentkey == $mnet_peer->public_key) { unset($currentkey); } $form = new stdClass(); if ($hostid != $CFG->mnet_all_hosts_id) { $credentials = $mnet_peer->check_credentials($mnet_peer->public_key); include './mnet_review.html'; } else { include './mnet_review_allhosts.html'; } } else { $hosts = $DB->get_records_sql(' SELECT h.id, h.wwwroot,
/** * The IdP uses this function to kill child sessions on other hosts * * @param string $username Username for session to kill * @param string $useragent SHA1 hash of user agent to look for * @return string A plaintext report of what has happened */ function kill_children($username, $useragent) { global $CFG, $USER, $DB; $remoteclient = null; if (defined('MNET_SERVER')) { $remoteclient = get_mnet_remote_client(); } require_once $CFG->dirroot . '/mnet/xmlrpc/client.php'; $userid = $DB->get_field('user', 'id', array('mnethostid' => $CFG->mnet_localhost_id, 'username' => $username)); $returnstring = ''; $mnetsessions = $DB->get_records('mnet_session', array('userid' => $userid, 'useragent' => $useragent)); if (false == $mnetsessions) { $returnstring .= "Could find no remote sessions\n"; $mnetsessions = array(); } foreach ($mnetsessions as $mnetsession) { // If this script is being executed by a remote peer, that means the user has clicked // logout on that peer, and the session on that peer can be deleted natively. // Skip over it. if (isset($remoteclient->id) && $mnetsession->mnethostid == $remoteclient->id) { continue; } $returnstring .= "Deleting session\n"; $mnet_peer = new mnet_peer(); $mnet_peer->set_id($mnetsession->mnethostid); $mnet_request = new mnet_xmlrpc_client(); $mnet_request->set_method('auth/mnet/auth.php/kill_child'); // set $token and $useragent parameters $mnet_request->add_param($username); $mnet_request->add_param($useragent); if ($mnet_request->send($mnet_peer) === false) { debugging("Server side error has occured on host {$mnetsession->mnethostid}: " . join("\n", $mnet_request->error)); } } $ignore = $DB->delete_records('mnet_session', array('useragent' => $useragent, 'userid' => $userid)); if (isset($remoteclient) && isset($remoteclient->id)) { session_kill_user($userid); } return $returnstring; }
/** * Returns the name of the current theme * * @uses $CFG * @uses $USER * @uses $SESSION * @uses $COURSE * @uses $SCRIPT * @return string */ function current_theme() { global $CFG, $USER, $SESSION, $COURSE, $SCRIPT; if (empty($CFG->themeorder)) { $themeorder = array('page', 'course', 'category', 'session', 'user', 'site'); } else { $themeorder = $CFG->themeorder; } if (isloggedin() and isset($CFG->mnet_localhost_id) and $USER->mnethostid != $CFG->mnet_localhost_id) { require_once $CFG->dirroot . '/mnet/peer.php'; $mnet_peer = new mnet_peer(); $mnet_peer->set_id($USER->mnethostid); } $theme = ''; foreach ($themeorder as $themetype) { if (!empty($theme)) { continue; } switch ($themetype) { case 'page': // Page theme is for special page-only themes set by code if (!empty($CFG->pagetheme)) { $theme = $CFG->pagetheme; } break; case 'course': if (!empty($CFG->allowcoursethemes) and !empty($COURSE->theme)) { $theme = $COURSE->theme; } break; case 'category': if (!empty($CFG->allowcategorythemes)) { /// Nasty hack to check if we're in a category page if ($SCRIPT == '/course/category.php') { global $id; if (!empty($id)) { $theme = current_category_theme($id); } /// Otherwise check if we're in a course that has a category theme set } else { if (!empty($COURSE->category)) { $theme = current_category_theme($COURSE->category); } } } break; case 'session': if (!empty($SESSION->theme)) { $theme = $SESSION->theme; } break; case 'user': if (!empty($CFG->allowuserthemes) and !empty($USER->theme)) { if (isloggedin() and $USER->mnethostid != $CFG->mnet_localhost_id && $mnet_peer->force_theme == 1 && $mnet_peer->theme != '') { $theme = $mnet_peer->theme; } else { $theme = $USER->theme; } } break; case 'site': if (isloggedin() and isset($CFG->mnet_localhost_id) and $USER->mnethostid != $CFG->mnet_localhost_id && $mnet_peer->force_theme == 1 && $mnet_peer->theme != '') { $theme = $mnet_peer->theme; } else { $theme = $CFG->theme; } break; default: /// do nothing } } /// A final check in case 'site' was not included in $CFG->themeorder if (empty($theme)) { $theme = $CFG->theme; } return $theme; }
/** * Describes the form, with the triplet (service_name, publish, subscribe). */ public function definition() { global $CFG, $SESSION, $DB; // Settings variables. $mform =& $this->_form; // Master services. $defaultservices = $DB->get_records('mnet_service', array('offer' => 1), 'name'); // get version info to get real names $self_mnet_peer = new mnet_peer(); $self_mnet_peer->set_id($CFG->mnet_localhost_id); $myservices = mnet_get_service_info($self_mnet_peer); if (!empty($defaultservices)) { // Services fieldset. $mform->addElement('header', 'servicesform', get_string('servicesformselection', 'local_vmoodle')); $grid =& $mform->addElement('elementgrid', 'grid', get_string('mainservicesformselection', 'local_vmoodle')); $row = array(); $row[] = get_string('publish', 'local_vmoodle'); $row[] = get_string('subscribe', 'local_vmoodle'); $row[] = ''; $row[] = ''; $grid->setColumnNames($row); foreach ($defaultservices as $defaultservice) { $row = array(); $row[] = $mform->createElement('advcheckbox', 'main_' . $defaultservice->name . '_publish'); $row[] = $mform->createElement('advcheckbox', 'main_' . $defaultservice->name . '_subscribe'); $row[] = $mform->createElement('static', 'main_' . $defaultservice->name . '_description'); $row[] = $mform->createElement('hidden', 'main_' . $defaultservice->name . '_id'); $description = $defaultservice->description; if (empty($description)) { $version = current($myservices[$defaultservice->name]); $langmodule = ($version['plugintype'] == 'mod' ? '' : $version['plugintype'] . '_') . $version['pluginname']; // TODO there should be a moodle-wide way to do this $description = get_string($defaultservice->name . '_name', $langmodule); } $mform->setDefault('main_' . $defaultservice->name . '_description', $description); $mform->setDefault('main_' . $defaultservice->name . '_id', $defaultservice->id); $mform->setType('main_' . $defaultservice->name . '_id', PARAM_INT); $grid->addRow($row); } // Services fieldset. $grid =& $mform->addElement('elementgrid', 'grid', get_string('peerservicesformselection', 'local_vmoodle')); $row = array(); $row[] = get_string('publish', 'local_vmoodle'); $row[] = get_string('subscribe', 'local_vmoodle'); $row[] = ''; $row[] = ''; $grid->setColumnNames($row); foreach ($defaultservices as $defaultservice) { $row = array(); $row[] = $mform->createElement('advcheckbox', 'peer_' . $defaultservice->name . '_publish'); $row[] = $mform->createElement('advcheckbox', 'peer_' . $defaultservice->name . '_subscribe'); $row[] = $mform->createElement('static', 'peer_' . $defaultservice->name . '_description'); $row[] = $mform->createElement('hidden', 'peer_' . $defaultservice->name . '_id'); $description = $defaultservice->description; if (empty($description)) { $version = current($myservices[$defaultservice->name]); $langmodule = ($version['plugintype'] == 'mod' ? '' : $version['plugintype'] . '_') . $version['pluginname']; // TODO there should be a moodle-wide way to do this $description = get_string($defaultservice->name . '_name', $langmodule); } $mform->setDefault('peer_' . $defaultservice->name . '_description', $description); $mform->setDefault('peer_' . $defaultservice->name . '_id', $defaultservice->id); $mform->setType('peer_' . $defaultservice->name . '_id', PARAM_INT); $grid->addRow($row); } // Submit button. $mform->addElement('submit', 'submitbutton', get_string('edit')); } else { // Confirmation message. $message_object = new stdclass(); $message_object->message = get_string('badservicesnumber', 'local_vmoodle'); $message_object->style = 'notifyproblem'; // Save confirm message before redirection. $SESSION->vmoodle_ma['confirm_message'] = $message_object; new moodle_url('/local/vmoodle/view.php', array('view' => 'management')); } }
/** * Send request to unenrol our user from the remote course * * Updates our remote enrolments cache if the unenrolment was successful. * * @uses mnet_xmlrpc_client Invokes XML-RPC request * @param object $user our user * @param object $remotecourse record from mnetservice_enrol_courses table * @return true|string true if success, error message from the remote host otherwise */ public function req_unenrol_user(stdclass $user, stdclass $remotecourse) { global $CFG, $DB; require_once $CFG->dirroot . '/mnet/xmlrpc/client.php'; $peer = new mnet_peer(); $peer->set_id($remotecourse->hostid); $request = new mnet_xmlrpc_client(); $request->set_method('enrol/mnet/enrol.php/unenrol_user'); $request->add_param($user->username); $request->add_param($remotecourse->remoteid); if ($request->send($peer) === true) { if ($request->response === true) { // clear the cached information $DB->delete_records('mnetservice_enrol_enrolments', array('hostid' => $peer->id, 'userid' => $user->id, 'remotecourseid' => $remotecourse->remoteid, 'enroltype' => 'mnet')); return true; } else { return serialize(array('invalid response: ' . print_r($request->response, true))); } } else { return serialize($request->error); } }
/** * Does Foo * * @param int $mnethostid The id of the remote mnethost * @return array Whether the user can login from the remote host */ function req_unenrol_user($userid, $courseid) { global $CFG; global $USER; global $MNET; require_once $CFG->dirroot . '/mnet/xmlrpc/client.php'; // in case the remote host doesn't have it $username = get_field('user', 'username', 'id', $userid); $course = get_record('mnet_enrol_course', 'id', $courseid); // get the Service Provider info $mnet_sp = new mnet_peer(); $mnet_sp->set_id($course->hostid); // set up the RPC request $mnetrequest = new mnet_xmlrpc_client(); $mnetrequest->set_method('enrol/mnet/enrol.php/unenrol_user'); $mnetrequest->add_param($username); $mnetrequest->add_param($course->remoteid); // TODO - prevent removal of enrolments that are not of // type mnet... // Thunderbirds are go! Do RPC call and store response if ($mnetrequest->send($mnet_sp) === true) { if ($mnetrequest->response == true) { // remove enrolment cached in mnet_enrol_assignments delete_records_select('mnet_enrol_assignments', "userid={$userid} AND courseid={$course->id}"); return true; } } return false; }
/** * The IdP uses this function to kill child sessions on other hosts * * @param string $username Username for session to kill * @param string $useragent SHA1 hash of user agent to look for * @return string A plaintext report of what has happened */ function kill_children($username, $useragent) { global $CFG, $USER, $MNET_REMOTE_CLIENT, $DB; require_once $CFG->dirroot . '/mnet/xmlrpc/client.php'; $userid = $DB->get_field('user', 'id', array('mnethostid' => $CFG->mnet_localhost_id, 'username' => $username)); $returnstring = ''; $mnetsessions = $DB->get_records('mnet_session', array('userid' => $userid, 'useragent' => $useragent)); if (false == $mnetsessions) { $returnstring .= "Could find no remote sessions\n"; $mnetsessions = array(); } foreach ($mnetsessions as $mnetsession) { // If this script is being executed by a remote peer, that means the user has clicked // logout on that peer, and the session on that peer can be deleted natively. // Skip over it. if (isset($MNET_REMOTE_CLIENT->id) && $mnetsession->mnethostid == $MNET_REMOTE_CLIENT->id) { continue; } $returnstring .= "Deleting session\n"; $mnet_peer = new mnet_peer(); $mnet_peer->set_id($mnetsession->mnethostid); $mnet_request = new mnet_xmlrpc_client(); $mnet_request->set_method('auth/mnet/auth.php/kill_child'); // set $token and $useragent parameters $mnet_request->add_param($username); $mnet_request->add_param($useragent); if ($mnet_request->send($mnet_peer) === false) { debugging("Server side error has occured on host {$mnetsession->mnethostid}: " . join("\n", $mnet_request->error)); } } $ignore = $DB->delete_records('mnet_session', array('useragent' => $useragent, 'userid' => $userid)); if (isset($MNET_REMOTE_CLIENT) && isset($MNET_REMOTE_CLIENT->id)) { $start = ob_start(); // Save current session and cookie-use status $cookieuse = ini_get('session.use_cookies'); ini_set('session.use_cookies', false); $sesscache = $_SESSION; $sessidcache = session_id(); // Replace existing mnet session with user session & unset session_write_close(); unset($_SESSION); session_id($mnetsession->session_id); session_start(); session_unregister("USER"); session_unregister("SESSION"); unset($_SESSION); $_SESSION = array(); session_write_close(); // Restore previous info ini_set('session.use_cookies', $cookieuse); session_name('MoodleSession' . $CFG->sessioncookie); session_id($sessidcache); session_start(); $_SESSION = $sesscache; session_write_close(); $end = ob_end_clean(); } else { $_SESSION = array(); } return $returnstring; }
/** * The IdP uses this function to kill child sessions on other hosts * * @param string $username Username for session to kill * @param string $useragent SHA1 hash of user agent to look for * @return string A plaintext report of what has happened */ function kill_children($username, $useragent) { global $CFG, $USER, $MNET_REMOTE_CLIENT; require_once $CFG->dirroot . '/mnet/xmlrpc/client.php'; $userid = get_field('user', 'id', 'mnethostid', $CFG->mnet_localhost_id, 'username', addslashes($username)); $returnstring = ''; $sql = "\n select\n *\n from\n {$CFG->prefix}mnet_session s\n where\n s.userid = '{$userid}' AND\n s.useragent = '{$useragent}'"; // If we are being executed from a remote machine (client) we don't have // to kill the moodle session on that machine. if (isset($MNET_REMOTE_CLIENT) && isset($MNET_REMOTE_CLIENT->id)) { $excludeid = $MNET_REMOTE_CLIENT->id; } else { $excludeid = -1; } $mnetsessions = get_records_sql($sql); if (false == $mnetsessions) { $returnstring .= "Could find no remote sessions\n{$sql}\n"; $mnetsessions = array(); } foreach ($mnetsessions as $mnetsession) { $returnstring .= "Deleting session\n"; if ($mnetsession->mnethostid == $excludeid) { continue; } $mnet_peer = new mnet_peer(); $mnet_peer->set_id($mnetsession->mnethostid); $mnet_request = new mnet_xmlrpc_client(); $mnet_request->set_method('auth/mnet/auth.php/kill_child'); // set $token and $useragent parameters $mnet_request->add_param($username); $mnet_request->add_param($useragent); if ($mnet_request->send($mnet_peer) === false) { debugging("Server side error has occured on host {$mnetsession->mnethostid}: " . join("\n", $mnet_request->error)); } } $ignore = delete_records('mnet_session', 'useragent', $useragent, 'userid', $userid); if (isset($MNET_REMOTE_CLIENT) && isset($MNET_REMOTE_CLIENT->id)) { $start = ob_start(); $uc = ini_get('session.use_cookies'); ini_set('session.use_cookies', false); $sesscache = clone $_SESSION; $sessidcache = session_id(); session_write_close(); unset($_SESSION); session_id($mnetsession->session_id); session_start(); session_unregister("USER"); session_unregister("SESSION"); unset($_SESSION); $_SESSION = array(); session_write_close(); ini_set('session.use_cookies', $uc); session_name('MoodleSession' . $CFG->sessioncookie); session_id($sessidcache); session_start(); $_SESSION = clone $sesscache; session_write_close(); $end = ob_end_clean(); } else { $_SESSION = array(); } return $returnstring; }
/** * Send the request to the server - decode and return the response * * @param object $mnet_peer A mnet_peer object with details of the * remote host we're connecting to * @return mixed A PHP variable, as returned by the * remote function */ function send($mnet_peer) { global $CFG, $DB; if (!$this->permission_to_call($mnet_peer)) { mnet_debug("tried and wasn't allowed to call a method on {$mnet_peer->wwwroot}"); return false; } $this->requesttext = xmlrpc_encode_request($this->method, $this->params, array("encoding" => "utf-8", "escaping" => "markup")); $this->signedrequest = mnet_sign_message($this->requesttext); $this->encryptedrequest = mnet_encrypt_message($this->signedrequest, $mnet_peer->public_key); $httprequest = $this->prepare_http_request($mnet_peer); curl_setopt($httprequest, CURLOPT_POSTFIELDS, $this->encryptedrequest); $timestamp_send = time(); mnet_debug("about to send the curl request"); $this->rawresponse = curl_exec($httprequest); mnet_debug("managed to complete a curl request"); $timestamp_receive = time(); if ($this->rawresponse === false) { $this->error[] = curl_errno($httprequest) . ':' . curl_error($httprequest); return false; } curl_close($httprequest); $this->rawresponse = trim($this->rawresponse); $mnet_peer->touch(); $crypt_parser = new mnet_encxml_parser(); $crypt_parser->parse($this->rawresponse); // If we couldn't parse the message, or it doesn't seem to have encrypted contents, // give the most specific error msg available & return if (!$crypt_parser->payload_encrypted) { if (!empty($crypt_parser->remoteerror)) { $this->error[] = '4: remote server error: ' . $crypt_parser->remoteerror; } else { if (!empty($crypt_parser->error)) { $crypt_parser_error = $crypt_parser->error[0]; $message = '3:XML Parse error in payload: ' . $crypt_parser_error['string'] . "\n"; if (array_key_exists('lineno', $crypt_parser_error)) { $message .= 'At line number: ' . $crypt_parser_error['lineno'] . "\n"; } if (array_key_exists('line', $crypt_parser_error)) { $message .= 'Which reads: ' . $crypt_parser_error['line'] . "\n"; } $this->error[] = $message; } else { $this->error[] = '1:Payload not encrypted '; } } $crypt_parser->free_resource(); return false; } $key = array_pop($crypt_parser->cipher); $data = array_pop($crypt_parser->cipher); $crypt_parser->free_resource(); // Initialize payload var $decryptedenvelope = ''; // &$decryptedenvelope $isOpen = openssl_open(base64_decode($data), $decryptedenvelope, base64_decode($key), $this->mnet->get_private_key()); if (!$isOpen) { // Decryption failed... let's try our archived keys $openssl_history = get_config('mnet', 'openssl_history'); if (empty($openssl_history)) { $openssl_history = array(); set_config('openssl_history', serialize($openssl_history), 'mnet'); } else { $openssl_history = unserialize($openssl_history); } foreach ($openssl_history as $keyset) { $keyresource = openssl_pkey_get_private($keyset['keypair_PEM']); $isOpen = openssl_open(base64_decode($data), $decryptedenvelope, base64_decode($key), $keyresource); if ($isOpen) { // It's an older code, sir, but it checks out break; } } } if (!$isOpen) { trigger_error("None of our keys could open the payload from host {$mnet_peer->wwwroot} with id {$mnet_peer->id}."); $this->error[] = '3:No key match'; return false; } if (strpos(substr($decryptedenvelope, 0, 100), '<signedMessage>')) { $sig_parser = new mnet_encxml_parser(); $sig_parser->parse($decryptedenvelope); } else { $this->error[] = '2:Payload not signed: ' . $decryptedenvelope; return false; } // Margin of error is the time it took the request to complete. $margin_of_error = $timestamp_receive - $timestamp_send; // Guess the time gap between sending the request and the remote machine // executing the time() function. Marginally better than nothing. $hysteresis = $margin_of_error / 2; $remote_timestamp = $sig_parser->remote_timestamp - $hysteresis; $time_offset = $remote_timestamp - $timestamp_send; if ($time_offset > 0) { $threshold = get_config('mnet', 'drift_threshold'); if (empty($threshold)) { // We decided 15 seconds was a pretty good arbitrary threshold // for time-drift between servers, but you can customize this in // the config_plugins table. It's not advised though. set_config('drift_threshold', 15, 'mnet'); $threshold = 15; } if ($time_offset > $threshold) { $this->error[] = '6:Time gap with ' . $mnet_peer->name . ' (' . $time_offset . ' seconds) is greater than the permitted maximum of ' . $threshold . ' seconds'; return false; } } $this->xmlrpcresponse = base64_decode($sig_parser->data_object); $this->response = xmlrpc_decode($this->xmlrpcresponse); // xmlrpc errors are pushed onto the $this->error stack if (is_array($this->response) && array_key_exists('faultCode', $this->response)) { // The faultCode 7025 means we tried to connect with an old SSL key // The faultString is the new key - let's save it and try again // The re_key attribute stops us from getting into a loop if ($this->response['faultCode'] == 7025 && empty($mnet_peer->re_key)) { mnet_debug('recieved an old-key fault, so trying to get the new key and update our records'); // If the new certificate doesn't come thru clean_param() unmolested, error out if ($this->response['faultString'] != clean_param($this->response['faultString'], PARAM_PEM)) { $this->error[] = $this->response['faultCode'] . " : " . $this->response['faultString']; } $record = new stdClass(); $record->id = $mnet_peer->id; $record->public_key = $this->response['faultString']; $details = openssl_x509_parse($record->public_key); if (!isset($details['validTo_time_t'])) { $this->error[] = $this->response['faultCode'] . " : " . $this->response['faultString']; } $record->public_key_expires = $details['validTo_time_t']; $DB->update_record('mnet_host', $record); // Create a new peer object populated with the new info & try re-sending the request $rekeyed_mnet_peer = new mnet_peer(); $rekeyed_mnet_peer->set_id($record->id); $rekeyed_mnet_peer->re_key = true; return $this->send($rekeyed_mnet_peer); } if (!empty($CFG->mnet_rpcdebug)) { if (get_string_manager()->string_exists('error' . $this->response['faultCode'], 'mnet')) { $guidance = get_string('error' . $this->response['faultCode'], 'mnet'); } else { $guidance = ''; } } else { $guidance = ''; } $this->error[] = $this->response['faultCode'] . " : " . $this->response['faultString'] . "\n" . $guidance; } // ok, it's signed, but is it signed with the right certificate ? // do this *after* we check for an out of date key if (!openssl_verify($this->xmlrpcresponse, base64_decode($sig_parser->signature), $mnet_peer->public_key)) { $this->error[] = 'Invalid signature'; } return empty($this->error); }
/** * Work out the theme this page should use. * * This depends on numerous $CFG settings, and the properties of this page. * * @return string the name of the theme that should be used on this page. */ protected function resolve_theme() { global $CFG, $USER, $SESSION; if (empty($CFG->themeorder)) { $themeorder = array('course', 'category', 'session', 'user', 'site'); } else { $themeorder = $CFG->themeorder; // Just in case, make sure we always use the site theme if nothing else matched. $themeorder[] = 'site'; } $mnetpeertheme = ''; if (isloggedin() and isset($CFG->mnet_localhost_id) and $USER->mnethostid != $CFG->mnet_localhost_id) { require_once($CFG->dirroot.'/mnet/peer.php'); $mnetpeer = new mnet_peer(); $mnetpeer->set_id($USER->mnethostid); if ($mnetpeer->force_theme == 1 && $mnetpeer->theme != '') { $mnetpeertheme = $mnetpeer->theme; } } $theme = ''; foreach ($themeorder as $themetype) { switch ($themetype) { case 'course': if (!empty($CFG->allowcoursethemes) and !empty($this->course->theme)) { return $this->course->theme; } case 'category': if (!empty($CFG->allowcategorythemes)) { $categories = $this->categories; foreach ($categories as $category) { if (!empty($category->theme)) { return $category->theme; } } } case 'session': if (!empty($SESSION->theme)) { return $SESSION->theme; } case 'user': if (!empty($CFG->allowuserthemes) and !empty($USER->theme)) { if ($mnetpeertheme) { return $mnetpeertheme; } else { return $USER->theme; } } case 'site': if ($mnetpeertheme) { return $mnetpeertheme; } else if(!empty($CFG->themelegacy) && $this->browser_is_outdated()) { $this->_legacythemeinuse = true; return $CFG->themelegacy; } else { return $CFG->theme; } } } }
public function callRemoteMethod($method, $parameters, $server = null) { global $CFG, $SynchServerController; require_once $CFG->dirroot . '/mnet/xmlrpc/client.php'; // For the demo, our 'remote' host is actually our local host. $wwwroot = $CFG->wwwroot; //$method = 'synch/mnet/synch.php/getBackupById'; // Get local server. $localServer = $SynchServerController->checkAndCreateLocalServer(); global $Out; //$Out->print_r($localServer, '$localServer = '); // Cannot continue without a local server if (empty($localServer)) { return null; } if (empty($server)) { //$Out->append('Generating default remote server'); //$server = new synch_modal_Server(); //$server->mnetHostId = 1020000003; $server = $SynchServerController->getRemoteServer(); } //$Out->print_r($server, '$server = '); // Cannot continue without a remote server to call if (empty($server) || synch_empty($server->mnetHostId)) { return null; } // mnet_peer pulls information about a remote host from the database. $mnet_peer = new mnet_peer(); $mnet_peer->set_wwwroot($wwwroot); $mnethostid = $server->mnetHostId; $mnet_peer->set_id($mnethostid); // Create a new request object $mnet_request = new mnet_xmlrpc_client(); // Tell it the path to the method that we want to execute $mnet_request->set_method($method); // Set the time out to something decent in seconds //$mnet_request->set_timeout(600); //set_time_limit(120); // Add parameters for your function. The mnet_concatenate_strings takes three // parameters, like mnet_concatenate_strings($string1, $string2, $string3) // PHP is weakly typed, so you can get away with calling most things strings, // unless it's non-scalar (i.e. an array or object or something). foreach ($parameters as $param) { $mnet_request->add_param($param[0], $param[1]); } // We send the request: $mnet_request->send($mnet_peer); return $mnet_request->response; }
/** * Work out the theme this page should use. * * This depends on numerous $CFG settings, and the properties of this page. * * @return string the name of the theme that should be used on this page. */ protected function resolve_theme() { global $CFG, $USER, $SESSION; if (empty($CFG->themeorder)) { $themeorder = array('course', 'category', 'session', 'user', 'site'); } else { $themeorder = $CFG->themeorder; // Just in case, make sure we always use the site theme if nothing else matched. $themeorder[] = 'site'; } $mnetpeertheme = ''; if (isloggedin() and isset($CFG->mnet_localhost_id) and $USER->mnethostid != $CFG->mnet_localhost_id) { require_once($CFG->dirroot.'/mnet/peer.php'); $mnetpeer = new mnet_peer(); $mnetpeer->set_id($USER->mnethostid); if ($mnetpeer->force_theme == 1 && $mnetpeer->theme != '') { $mnetpeertheme = $mnetpeer->theme; } } foreach ($themeorder as $themetype) { switch ($themetype) { case 'course': if (!empty($CFG->allowcoursethemes) && !empty($this->_course->theme) && $this->devicetypeinuse == 'default') { return $this->_course->theme; } case 'category': if (!empty($CFG->allowcategorythemes) && $this->devicetypeinuse == 'default') { $categories = $this->categories; foreach ($categories as $category) { if (!empty($category->theme)) { return $category->theme; } } } case 'session': if (!empty($SESSION->theme)) { return $SESSION->theme; } case 'user': if (!empty($CFG->allowuserthemes) && !empty($USER->theme) && $this->devicetypeinuse == 'default') { if ($mnetpeertheme) { return $mnetpeertheme; } else { return $USER->theme; } } case 'site': if ($mnetpeertheme) { return $mnetpeertheme; } // First try for the device the user is using. $devicetheme = get_selected_theme_for_device_type($this->devicetypeinuse); if (!empty($devicetheme)) { return $devicetheme; } // Next try for the default device (as a fallback) $devicetheme = get_selected_theme_for_device_type('default'); if (!empty($devicetheme)) { return $devicetheme; } // The default device theme isn't set up - use the overall default theme. return theme_config::DEFAULT_THEME; } } }
// Yes, enrol is correct English spelling. require_once dirname(__FILE__) . "/../../config.php"; require_once $CFG->libdir . '/adminlib.php'; include_once $CFG->dirroot . '/mnet/xmlrpc/client.php'; if (!confirm_sesskey()) { error(get_string('confirmsesskeybad', 'error')); } admin_externalpage_setup('mnetenrol'); $CFG->pagepath = 'admin/mnet'; require_once "{$CFG->dirroot}/enrol/enrol.class.php"; /// Open the factory class $enrolment = enrolment_factory::factory('mnet'); $mnethostid = required_param('host', PARAM_INT); $courseid = required_param('courseid', PARAM_INT); $mnet_peer = new mnet_peer(); if (!$mnet_peer->set_id($mnethostid)) { print_error('hostcoursenotfound', 'mnet'); } $course = get_record('mnet_enrol_course', 'id', $courseid, 'hostid', $mnet_peer->id); if (empty($course)) { print_error('hostcoursenotfound', 'mnet'); } define("MAX_USERS_PER_PAGE", 5000); $add = optional_param('add', 0, PARAM_BOOL); $remove = optional_param('remove', 0, PARAM_BOOL); $showall = optional_param('showall', 0, PARAM_BOOL); $searchtext = optional_param('searchtext', '', PARAM_RAW); // search string $previoussearch = optional_param('previoussearch', 0, PARAM_BOOL); $userid = optional_param('userid', 0, PARAM_INT); // needed for user tabs
/** * This function is used to generate and display Mnet selector form * * @global stdClass $USER * @global stdClass $CFG * @global stdClass $SITE * @global moodle_database $DB * @global core_renderer $OUTPUT * @global stdClass $SESSION * @uses CONTEXT_SYSTEM * @uses COURSE_MAX_COURSES_PER_DROPDOWN * @uses CONTEXT_COURSE * @uses SEPARATEGROUPS * @param int $hostid host id * @param stdClass $course course instance * @param int $selecteduser id of the selected user * @param string $selecteddate Date selected * @param string $modname course_module->id * @param string $modid number or 'site_errors' * @param string $modaction an action as recorded in the logs * @param int $selectedgroup Group to display * @param int $showcourses whether to show courses if we're over our limit. * @param int $showusers whether to show users if we're over our limit. * @param string $logformat Format of the logs (downloadascsv, showashtml, downloadasods, downloadasexcel) * @return void */ function report_log_print_mnet_selector_form($hostid, $course, $selecteduser = 0, $selecteddate = 'today', $modname = "", $modid = 0, $modaction = '', $selectedgroup = -1, $showcourses = 0, $showusers = 0, $logformat = 'showashtml') { global $USER, $CFG, $SITE, $DB, $OUTPUT, $SESSION; require_once $CFG->dirroot . '/mnet/peer.php'; $mnet_peer = new mnet_peer(); $mnet_peer->set_id($hostid); $sql = "SELECT DISTINCT course, hostid, coursename FROM {mnet_log}"; $courses = $DB->get_records_sql($sql); $remotecoursecount = count($courses); // first check to see if we can override showcourses and showusers $numcourses = $remotecoursecount + $DB->count_records('course'); if ($numcourses < COURSE_MAX_COURSES_PER_DROPDOWN && !$showcourses) { $showcourses = 1; } $sitecontext = get_context_instance(CONTEXT_SYSTEM); // Context for remote data is always SITE // Groups for remote data are always OFF if ($hostid == $CFG->mnet_localhost_id) { $context = get_context_instance(CONTEXT_COURSE, $course->id); /// Setup for group handling. if ($course->groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) { $selectedgroup = -1; $showgroups = false; } else { if ($course->groupmode) { $showgroups = true; } else { $selectedgroup = 0; $showgroups = false; } } if ($selectedgroup === -1) { if (isset($SESSION->currentgroup[$course->id])) { $selectedgroup = $SESSION->currentgroup[$course->id]; } else { $selectedgroup = groups_get_all_groups($course->id, $USER->id); if (is_array($selectedgroup)) { $selectedgroup = array_shift(array_keys($selectedgroup)); $SESSION->currentgroup[$course->id] = $selectedgroup; } else { $selectedgroup = 0; } } } } else { $context = $sitecontext; } // Get all the possible users $users = array(); // Define limitfrom and limitnum for queries below // If $showusers is enabled... don't apply limitfrom and limitnum $limitfrom = empty($showusers) ? 0 : ''; $limitnum = empty($showusers) ? COURSE_MAX_USERS_PER_DROPDOWN + 1 : ''; // If looking at a different host, we're interested in all our site users if ($hostid == $CFG->mnet_localhost_id && $course->id != SITEID) { $courseusers = get_enrolled_users($context, '', $selectedgroup, 'u.id, u.firstname, u.lastname, u.idnumber', 'lastname ASC, firstname ASC', $limitfrom, $limitnum); } else { // this may be a lot of users :-( $courseusers = $DB->get_records('user', array('deleted' => 0), 'lastaccess DESC', 'id, firstname, lastname, idnumber', $limitfrom, $limitnum); } if (count($courseusers) < COURSE_MAX_USERS_PER_DROPDOWN && !$showusers) { $showusers = 1; } if ($showusers) { if ($courseusers) { foreach ($courseusers as $courseuser) { $users[$courseuser->id] = fullname($courseuser, has_capability('moodle/site:viewfullnames', $context)); } } $users[$CFG->siteguest] = get_string('guestuser'); } // Get all the hosts that have log records $sql = "select distinct\n h.id,\n h.name\n from\n {mnet_host} h,\n {mnet_log} l\n where\n h.id = l.hostid\n order by\n h.name"; if ($hosts = $DB->get_records_sql($sql)) { foreach ($hosts as $host) { $hostarray[$host->id] = $host->name; } } $hostarray[$CFG->mnet_localhost_id] = $SITE->fullname; asort($hostarray); $dropdown = array(); foreach ($hostarray as $hostid => $name) { $courses = array(); $sites = array(); if ($CFG->mnet_localhost_id == $hostid) { if (has_capability('report/log:view', $sitecontext) && $showcourses) { if ($ccc = $DB->get_records("course", null, "fullname", "id,shortname,fullname,category")) { foreach ($ccc as $cc) { if ($cc->id == SITEID) { $sites["{$hostid}/{$cc->id}"] = format_string($cc->fullname) . ' (' . get_string('site') . ')'; } else { $courses["{$hostid}/{$cc->id}"] = format_string(get_course_display_name_for_list($cc)); } } } } } else { if (has_capability('report/log:view', $sitecontext) && $showcourses) { $sql = "SELECT DISTINCT course, coursename FROM {mnet_log} where hostid = ?"; if ($ccc = $DB->get_records_sql($sql, array($hostid))) { foreach ($ccc as $cc) { if (1 == $cc->course) { // TODO: this might be wrong - site course may have another id $sites["{$hostid}/{$cc->course}"] = $cc->coursename . ' (' . get_string('site') . ')'; } else { $courses["{$hostid}/{$cc->course}"] = $cc->coursename; } } } } } asort($courses); $dropdown[] = array($name => $sites + $courses); } $activities = array(); $selectedactivity = ""; /// Casting $course->modinfo to string prevents one notice when the field is null if ($modinfo = unserialize((string) $course->modinfo)) { $section = 0; $sections = get_all_sections($course->id); foreach ($modinfo as $mod) { if ($mod->mod == "label") { continue; } if ($mod->section > 0 and $section != $mod->section) { $activities["section/{$mod->section}"] = '--- ' . get_section_name($course, $sections[$mod->section]) . ' ---'; } $section = $mod->section; $mod->name = strip_tags(format_string($mod->name, true)); if (textlib::strlen($mod->name) > 55) { $mod->name = textlib::substr($mod->name, 0, 50) . "..."; } if (!$mod->visible) { $mod->name = "(" . $mod->name . ")"; } $activities["{$mod->cm}"] = $mod->name; if ($mod->cm == $modid) { $selectedactivity = "{$mod->cm}"; } } } if (has_capability('report/log:view', $sitecontext) && !$course->category) { $activities["site_errors"] = get_string("siteerrors"); if ($modid === "site_errors") { $selectedactivity = "site_errors"; } } $strftimedate = get_string("strftimedate"); $strftimedaydate = get_string("strftimedaydate"); asort($users); // Prepare the list of action options. $actions = array('view' => get_string('view'), 'add' => get_string('add'), 'update' => get_string('update'), 'delete' => get_string('delete'), '-view' => get_string('allchanges')); // Get all the possible dates // Note that we are keeping track of real (GMT) time and user time // User time is only used in displays - all calcs and passing is GMT $timenow = time(); // GMT // What day is it now for the user, and when is midnight that day (in GMT). $timemidnight = $today = usergetmidnight($timenow); // Put today up the top of the list $dates = array("0" => get_string('alldays'), "{$timemidnight}" => get_string("today") . ", " . userdate($timenow, $strftimedate)); if (!$course->startdate or $course->startdate > $timenow) { $course->startdate = $course->timecreated; } $numdates = 1; while ($timemidnight > $course->startdate and $numdates < 365) { $timemidnight = $timemidnight - 86400; $timenow = $timenow - 86400; $dates["{$timemidnight}"] = userdate($timenow, $strftimedaydate); $numdates++; } if ($selecteddate === "today") { $selecteddate = $today; } echo "<form class=\"logselectform\" action=\"{$CFG->wwwroot}/report/log/index.php\" method=\"get\">\n"; echo "<div>\n"; //invisible fieldset here breaks wrapping echo "<input type=\"hidden\" name=\"chooselog\" value=\"1\" />\n"; echo "<input type=\"hidden\" name=\"showusers\" value=\"{$showusers}\" />\n"; echo "<input type=\"hidden\" name=\"showcourses\" value=\"{$showcourses}\" />\n"; if (has_capability('report/log:view', $sitecontext) && $showcourses) { $cid = empty($course->id) ? '1' : $course->id; echo html_writer::label(get_string('selectacoursesite'), 'menuhost_course', false, array('class' => 'accesshide')); echo html_writer::select($dropdown, "host_course", $hostid . '/' . $cid); } else { $courses = array(); $courses[$course->id] = get_course_display_name_for_list($course) . (empty($course->category) ? ' (' . get_string('site') . ') ' : ''); echo html_writer::label(get_string('selectacourse'), 'menuid', false, array('class' => 'accesshide')); echo html_writer::select($courses, "id", $course->id, false); if (has_capability('report/log:view', $sitecontext)) { $a = new stdClass(); $a->url = "{$CFG->wwwroot}/report/log/index.php?chooselog=0&group={$selectedgroup}&user={$selecteduser}" . "&id={$course->id}&date={$selecteddate}&modid={$selectedactivity}&showcourses=1&showusers={$showusers}"; print_string('logtoomanycourses', 'moodle', $a); } } if ($showgroups) { if ($cgroups = groups_get_all_groups($course->id)) { foreach ($cgroups as $cgroup) { $groups[$cgroup->id] = $cgroup->name; } } else { $groups = array(); } echo html_writer::label(get_string('selectagroup'), 'menugroup', false, array('class' => 'accesshide')); echo html_writer::select($groups, "group", $selectedgroup, get_string("allgroups")); } if ($showusers) { echo html_writer::label(get_string('participantslist'), 'menuuser', false, array('class' => 'accesshide')); echo html_writer::select($users, "user", $selecteduser, get_string("allparticipants")); } else { $users = array(); if (!empty($selecteduser)) { $user = $DB->get_record('user', array('id' => $selecteduser)); $users[$selecteduser] = fullname($user); } else { $users[0] = get_string('allparticipants'); } echo html_writer::label(get_string('participantslist'), 'menuuser', false, array('class' => 'accesshide')); echo html_writer::select($users, "user", $selecteduser, false); $a->url = "{$CFG->wwwroot}/report/log/index.php?chooselog=0&group={$selectedgroup}&user={$selecteduser}" . "&id={$course->id}&date={$selecteddate}&modid={$selectedactivity}&showusers=1&showcourses={$showcourses}"; print_string('logtoomanyusers', 'moodle', $a); } echo html_writer::label(get_string('date'), 'menudate', false, array('class' => 'accesshide')); echo html_writer::select($dates, "date", $selecteddate, false); echo html_writer::label(get_string('showreports'), 'menumodid', false, array('class' => 'accesshide')); echo html_writer::select($activities, "modid", $selectedactivity, get_string("allactivities")); echo html_writer::label(get_string('actions'), 'menumodaction', false, array('class' => 'accesshide')); echo html_writer::select($actions, 'modaction', $modaction, get_string("allactions")); $logformats = array('showashtml' => get_string('displayonpage'), 'downloadascsv' => get_string('downloadtext'), 'downloadasods' => get_string('downloadods'), 'downloadasexcel' => get_string('downloadexcel')); echo html_writer::label(get_string('logsformat', 'report_log'), 'menulogformat', false, array('class' => 'accesshide')); echo html_writer::select($logformats, 'logformat', $logformat, false); echo '<input type="submit" value="' . get_string('gettheselogs') . '" />'; echo '</div>'; echo '</form>'; }
function print_mnet_log_selector_form($hostid, $course, $selecteduser = 0, $selecteddate = 'today', $modname = "", $modid = 0, $modaction = '', $selectedgroup = -1, $showcourses = 0, $showusers = 0, $logformat = 'showashtml') { global $USER, $CFG, $SITE; require_once $CFG->dirroot . '/mnet/peer.php'; $mnet_peer = new mnet_peer(); $mnet_peer->set_id($hostid); $sql = "select distinct course, hostid, coursename from {$CFG->prefix}mnet_log"; $courses = get_records_sql($sql); $remotecoursecount = count($courses); // first check to see if we can override showcourses and showusers $numcourses = $remotecoursecount + count_records_select("course", "", "COUNT(id)"); if ($numcourses < COURSE_MAX_COURSES_PER_DROPDOWN && !$showcourses) { $showcourses = 1; } $sitecontext = get_context_instance(CONTEXT_SYSTEM, SITEID); // Context for remote data is always SITE // Groups for remote data are always OFF if ($hostid == $CFG->mnet_localhost_id) { $context = get_context_instance(CONTEXT_COURSE, $course->id); /// Setup for group handling. if ($course->groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) { $selectedgroup = get_current_group($course->id); $showgroups = false; } else { if ($course->groupmode) { $selectedgroup = $selectedgroup == -1 ? get_current_group($course->id) : $selectedgroup; $showgroups = true; } else { $selectedgroup = 0; $showgroups = false; } } } else { $context = $sitecontext; } // Get all the possible users $users = array(); // If looking at a different host, we're interested in all our site users if ($hostid == $CFG->mnet_localhost_id && $course->id != SITEID) { if ($selectedgroup) { // If using a group, only get users in that group. $courseusers = get_group_users($selectedgroup, 'u.lastname ASC', '', 'u.id, u.firstname, u.lastname, u.idnumber'); } else { $courseusers = get_course_users($course->id, '', '', 'u.id, u.firstname, u.lastname, u.idnumber'); } } else { $courseusers = get_site_users("u.lastaccess DESC", "u.id, u.firstname, u.lastname, u.idnumber"); } if (count($courseusers) < COURSE_MAX_USERS_PER_DROPDOWN && !$showusers) { $showusers = 1; } if ($showusers) { if ($courseusers) { foreach ($courseusers as $courseuser) { $users[$courseuser->id] = fullname($courseuser, has_capability('moodle/site:viewfullnames', $context)); } } if ($guest = get_guest()) { $users[$guest->id] = fullname($guest); } } // Get all the hosts that have log records $sql = "select distinct\n h.id,\n h.name\n from\n {$CFG->prefix}mnet_host h,\n {$CFG->prefix}mnet_log l\n where\n h.id = l.hostid\n order by\n h.name"; if ($hosts = get_records_sql($sql)) { foreach ($hosts as $host) { $hostarray[$host->id] = $host->name; } } $hostarray[$CFG->mnet_localhost_id] = $SITE->fullname; asort($hostarray); foreach ($hostarray as $hostid => $name) { $courses = array(); $sites = array(); if ($CFG->mnet_localhost_id == $hostid) { if (has_capability('moodle/site:viewreports', $sitecontext) && $showcourses) { if ($ccc = get_records("course", "", "", "fullname", "id,fullname,category")) { foreach ($ccc as $cc) { if ($cc->id == SITEID) { $sites["{$hostid}/{$cc->id}"] = format_string($cc->fullname) . ' (' . get_string('site') . ')'; } else { $courses["{$hostid}/{$cc->id}"] = format_string($cc->fullname); } } } } } else { if (has_capability('moodle/site:viewreports', $sitecontext) && $showcourses) { $sql = "select distinct course, coursename from {$CFG->prefix}mnet_log where hostid = '{$hostid}'"; if ($ccc = get_records_sql($sql)) { foreach ($ccc as $cc) { if (1 == $cc->course) { // TODO: this might be wrong - site course may have another id $sites["{$hostid}/{$cc->course}"] = $cc->coursename . ' (' . get_string('site') . ')'; } else { $courses["{$hostid}/{$cc->course}"] = $cc->coursename; } } } } } asort($courses); $dropdown[$name] = $sites + $courses; } $activities = array(); $selectedactivity = ""; /// Casting $course->modinfo to string prevents one notice when the field is null if ($modinfo = unserialize((string) $course->modinfo)) { $section = 0; if ($course->format == 'weeks') { // Bodgy $strsection = get_string("week"); } else { $strsection = get_string("topic"); } foreach ($modinfo as $mod) { if ($mod->mod == "label") { continue; } if ($mod->section > 0 and $section != $mod->section) { $activities["section/{$mod->section}"] = "-------------- {$strsection} {$mod->section} --------------"; } $section = $mod->section; $mod->name = strip_tags(format_string(urldecode($mod->name), true)); if (strlen($mod->name) > 55) { $mod->name = substr($mod->name, 0, 50) . "..."; } if (!$mod->visible) { $mod->name = "(" . $mod->name . ")"; } $activities["{$mod->cm}"] = $mod->name; if ($mod->cm == $modid) { $selectedactivity = "{$mod->cm}"; } } } if (has_capability('moodle/site:viewreports', $sitecontext) && !$course->category) { $activities["site_errors"] = get_string("siteerrors"); if ($modid === "site_errors") { $selectedactivity = "site_errors"; } } $strftimedate = get_string("strftimedate"); $strftimedaydate = get_string("strftimedaydate"); asort($users); // Prepare the list of action options. $actions = array('view' => get_string('view'), 'add' => get_string('add'), 'update' => get_string('update'), 'delete' => get_string('delete'), '-view' => get_string('allchanges')); // Get all the possible dates // Note that we are keeping track of real (GMT) time and user time // User time is only used in displays - all calcs and passing is GMT $timenow = time(); // GMT // What day is it now for the user, and when is midnight that day (in GMT). $timemidnight = $today = usergetmidnight($timenow); // Put today up the top of the list $dates = array("{$timemidnight}" => get_string("today") . ", " . userdate($timenow, $strftimedate)); if (!$course->startdate or $course->startdate > $timenow) { $course->startdate = $course->timecreated; } $numdates = 1; while ($timemidnight > $course->startdate and $numdates < 365) { $timemidnight = $timemidnight - 86400; $timenow = $timenow - 86400; $dates["{$timemidnight}"] = userdate($timenow, $strftimedaydate); $numdates++; } if ($selecteddate == "today") { $selecteddate = $today; } echo "<form class=\"logselectform\" action=\"{$CFG->wwwroot}/course/report/log/index.php\" method=\"get\">\n"; echo "<div>\n"; //invisible fieldset here breaks wrapping echo "<input type=\"hidden\" name=\"chooselog\" value=\"1\" />\n"; echo "<input type=\"hidden\" name=\"showusers\" value=\"{$showusers}\" />\n"; echo "<input type=\"hidden\" name=\"showcourses\" value=\"{$showcourses}\" />\n"; if (has_capability('moodle/site:viewreports', $sitecontext) && $showcourses) { $cid = empty($course->id) ? '1' : $course->id; choose_from_menu_nested($dropdown, "host_course", $hostid . '/' . $cid, ""); } else { $courses = array(); $courses[$course->id] = $course->fullname . (empty($course->category) ? ' (' . get_string('site') . ') ' : ''); choose_from_menu($courses, "id", $course->id, false); if (has_capability('moodle/site:viewreports', $sitecontext)) { $a = new object(); $a->url = "{$CFG->wwwroot}/course/report/log/index.php?chooselog=0&group={$selectedgroup}&user={$selecteduser}" . "&id={$course->id}&date={$selecteddate}&modid={$selectedactivity}&showcourses=1&showusers={$showusers}"; print_string('logtoomanycourses', 'moodle', $a); } } if ($showgroups) { if ($cgroups = groups_get_all_groups($course->id)) { foreach ($cgroups as $cgroup) { $groups[$cgroup->id] = $cgroup->name; } } else { $groups = array(); } choose_from_menu($groups, "group", $selectedgroup, get_string("allgroups")); } if ($showusers) { choose_from_menu($users, "user", $selecteduser, get_string("allparticipants")); } else { $users = array(); if (!empty($selecteduser)) { $user = get_record('user', 'id', $selecteduser); $users[$selecteduser] = fullname($user); } else { $users[0] = get_string('allparticipants'); } choose_from_menu($users, 'user', $selecteduser, false); $a->url = "{$CFG->wwwroot}/course/report/log/index.php?chooselog=0&group={$selectedgroup}&user={$selecteduser}" . "&id={$course->id}&date={$selecteddate}&modid={$selectedactivity}&showusers=1&showcourses={$showcourses}"; print_string('logtoomanyusers', 'moodle', $a); } choose_from_menu($dates, "date", $selecteddate, get_string("alldays")); choose_from_menu($activities, "modid", $selectedactivity, get_string("allactivities"), "", ""); choose_from_menu($actions, 'modaction', $modaction, get_string("allactions")); $logformats = array('showashtml' => get_string('displayonpage'), 'downloadascsv' => get_string('downloadtext'), 'downloadasods' => get_string('downloadods'), 'downloadasexcel' => get_string('downloadexcel')); choose_from_menu($logformats, 'logformat', $logformat, false); echo '<input type="submit" value="' . get_string('gettheselogs') . '" />'; echo '</div>'; echo '</form>'; }
/** * Send Mnet request to Mahara portfolio. * * @global stdClass $CFG * @param string $methodname name of remote method to call * @param array $parameters list of method parameters * @return mixed $responsedata Mnet response */ private function mnet_send_request($methodname, $parameters) { global $CFG; $error = false; $responsedata = false; if (!is_enabled_auth('mnet')) { $error = get_string('authmnetdisabled', 'mnet'); } else { if (!has_capability('moodle/site:mnetlogintoremote', context_system::instance())) { $error = get_string('notpermittedtojump', 'mnet'); } else { // Set up the RPC request. require_once $CFG->dirroot . '/mnet/xmlrpc/client.php'; require_once $CFG->dirroot . '/mnet/peer.php'; $mnetpeer = new mnet_peer(); $mnetpeer->set_id($this->get_config('mnethostid')); $mnetrequest = new mnet_xmlrpc_client(); $mnetrequest->set_method('mod/mahara/rpclib.php/' . $methodname); foreach ($parameters as $parameter) { $mnetrequest->add_param($parameter); } if ($mnetrequest->send($mnetpeer) === true) { $responsedata = $mnetrequest->response; } else { $error = "RPC mod/mahara/rpclib.php/" . $methodname . ":<br/>"; foreach ($mnetrequest->error as $errormessage) { list($code, $errormessage) = array_map('trim', explode(':', $errormessage, 2)); $error .= "ERROR {$code}:<br/>{$errormessage}<br/>"; } } } } if ($error) { $this->set_error($error); } return $responsedata; }