/** * Returns location information * @param string $ip * @return array */ function iplookup_find_location($ip) { global $CFG; $info = array('city' => null, 'country' => null, 'longitude' => null, 'latitude' => null, 'error' => null, 'note' => '', 'title' => array()); if (!empty($CFG->geoip2file) and file_exists($CFG->geoip2file)) { $reader = new GeoIp2\Database\Reader($CFG->geoip2file); $record = $reader->city($ip); if (empty($record)) { $info['error'] = get_string('iplookupfailed', 'error', $ip); return $info; } $info['city'] = core_text::convert($record->city->name, 'iso-8859-1', 'utf-8'); $info['title'][] = $info['city']; $countrycode = $record->country->isoCode; $countries = get_string_manager()->get_list_of_countries(true); if (isset($countries[$countrycode])) { // Prefer our localized country names. $info['country'] = $countries[$countrycode]; } else { $info['country'] = $record->country->names['en']; } $info['title'][] = $info['country']; $info['longitude'] = $record->location->longitude; $info['latitude'] = $record->location->latitude; $info['note'] = get_string('iplookupmaxmindnote', 'admin'); return $info; } else { require_once $CFG->libdir . '/filelib.php'; if (strpos($ip, ':') !== false) { // IPv6 is not supported by geoplugin.net. $info['error'] = get_string('invalidipformat', 'error'); return $info; } $ipdata = download_file_content('http://www.geoplugin.net/json.gp?ip=' . $ip); if ($ipdata) { $ipdata = preg_replace('/^geoPlugin\\((.*)\\)\\s*$/s', '$1', $ipdata); $ipdata = json_decode($ipdata, true); } if (!is_array($ipdata)) { $info['error'] = get_string('cannotgeoplugin', 'error'); return $info; } $info['latitude'] = (double) $ipdata['geoplugin_latitude']; $info['longitude'] = (double) $ipdata['geoplugin_longitude']; $info['city'] = s($ipdata['geoplugin_city']); $countrycode = $ipdata['geoplugin_countryCode']; $countries = get_string_manager()->get_list_of_countries(true); if (isset($countries[$countrycode])) { // prefer our localized country names $info['country'] = $countries[$countrycode]; } else { $info['country'] = s($ipdata['geoplugin_countryName']); } $info['note'] = get_string('iplookupgeoplugin', 'admin'); $info['title'][] = $info['city']; $info['title'][] = $info['country']; return $info; } }
/** * Gets quoted csv variable string. * * @param string $varstr csv variable string * @return quoted csv variable string */ public function quote($varstr) { if ($this->_excelcsv) { return core_text::convert('"' . str_replace('"', "'", $varstr) . '"', 'UTF-8', 'UTF-16LE'); } else { return '"' . str_replace('"', "'", $varstr) . '"'; } }
function csv_quote($value) { global $excel; if ($excel) { return core_text::convert('"' . str_replace('"', "'", $value) . '"', 'UTF-8', 'UTF-16LE'); } else { return '"' . str_replace('"', "'", $value) . '"'; } }
/** * Authenticates user against the selected authentication provide (Ad web service) * * @param string $username The username (with system magic quotes) * @param string $password The password (with system magic quotes) * @return bool Authentication success or failure. */ function user_login($username, $password) { global $DB, $CFG; $extusername = core_text::convert($username, 'utf-8', $this->config->extencoding); $extpassword = core_text::convert($password, 'utf-8', $this->config->extencoding); if (!$username or !$password) { // Don't allow blank usernames or passwords return false; } //retrieve the user matching username if ($user = $DB->get_record('user', array('username' => $username, 'mnethostid' => $CFG->mnet_localhost_id, 'auth' => $this->authtype))) { return validate_internal_user_password($user, $password); } else { return false; } //username must exist and have the right authentication method if (!empty($user) && $user->auth == 'adwebservice') { return true; } return false; }
/** * Process flatfile. * @param progress_trace $trace * @return bool true if any data processed, false if not */ protected function process_file(progress_trace $trace) { global $CFG, $DB; // We may need more memory here. core_php_time_limit::raise(); raise_memory_limit(MEMORY_HUGE); $filelocation = $this->get_config('location'); if (empty($filelocation)) { // Default legacy location. $filelocation = "{$CFG->dataroot}/1/enrolments.txt"; } $disclosefile = $this->obfuscate_filepath($filelocation); if (!file_exists($filelocation)) { $trace->output("Flatfile enrolments file not found: {$disclosefile}"); $trace->finished(); return false; } $trace->output("Processing flat file enrolments from: {$disclosefile} ..."); $content = file_get_contents($filelocation); if ($content !== false) { $rolemap = $this->get_role_map($trace); $content = core_text::convert($content, $this->get_config('encoding', 'utf-8'), 'utf-8'); $content = str_replace("\r", '', $content); $content = explode("\n", $content); $line = 0; foreach ($content as $fields) { $line++; if (trim($fields) === '') { // Empty lines are ignored. continue; } // Deal with different separators. if (strpos($fields, ',') !== false) { $fields = explode(',', $fields); } else { $fields = explode(';', $fields); } // If a line is incorrectly formatted ie does not have 4 comma separated fields then ignore it. if (count($fields) < 4 or count($fields) > 6) { $trace->output("Line incorrectly formatted - ignoring {$line}", 1); continue; } $fields[0] = trim(core_text::strtolower($fields[0])); $fields[1] = trim(core_text::strtolower($fields[1])); $fields[2] = trim($fields[2]); $fields[3] = trim($fields[3]); $fields[4] = isset($fields[4]) ? (int) trim($fields[4]) : 0; $fields[5] = isset($fields[5]) ? (int) trim($fields[5]) : 0; // Deal with quoted values - all or nothing, we need to support "' in idnumbers, sorry. if (strpos($fields[0], "'") === 0) { foreach ($fields as $k => $v) { $fields[$k] = trim($v, "'"); } } else { if (strpos($fields[0], '"') === 0) { foreach ($fields as $k => $v) { $fields[$k] = trim($v, '"'); } } } $trace->output("{$line}: {$fields['0']}, {$fields['1']}, {$fields['2']}, {$fields['3']}, {$fields['4']}, {$fields['5']}", 1); // Check correct formatting of operation field. if ($fields[0] !== "add" and $fields[0] !== "del") { $trace->output("Unknown operation in field 1 - ignoring line {$line}", 1); continue; } // Check correct formatting of role field. if (!isset($rolemap[$fields[1]])) { $trace->output("Unknown role in field2 - ignoring line {$line}", 1); continue; } $roleid = $rolemap[$fields[1]]; if (empty($fields[2]) or !($user = $DB->get_record("user", array("idnumber" => $fields[2], 'deleted' => 0)))) { $trace->output("Unknown user idnumber or deleted user in field 3 - ignoring line {$line}", 1); continue; } if (!($course = $DB->get_record("course", array("idnumber" => $fields[3])))) { $trace->output("Unknown course idnumber in field 4 - ignoring line {$line}", 1); continue; } if ($fields[4] > $fields[5] and $fields[5] != 0) { $trace->output("Start time was later than end time - ignoring line {$line}", 1); continue; } $this->process_records($trace, $fields[0], $roleid, $user, $course, $fields[4], $fields[5]); } unset($content); } if (!unlink($filelocation)) { $eventdata = new stdClass(); $eventdata->modulename = 'moodle'; $eventdata->component = 'enrol_flatfile'; $eventdata->name = 'flatfile_enrolment'; $eventdata->userfrom = get_admin(); $eventdata->userto = get_admin(); $eventdata->subject = get_string('filelockedmailsubject', 'enrol_flatfile'); $eventdata->fullmessage = get_string('filelockedmail', 'enrol_flatfile', $filelocation); $eventdata->fullmessageformat = FORMAT_PLAIN; $eventdata->fullmessagehtml = ''; $eventdata->smallmessage = ''; message_send($eventdata); $trace->output("Error deleting enrolment file: {$disclosefile}", 1); } else { $trace->output("Deleted enrolment file", 1); } $trace->output("...finished enrolment file processing."); $trace->finished(); return true; }
/** * Create a map of file names used in zip archive. * @return void */ protected function init_namelookup() { if ($this->emptyziphack) { $this->namelookup = array(); return; } if (!isset($this->za)) { return; } if (isset($this->namelookup)) { return; } $this->namelookup = array(); if ($this->mode != file_archive::OPEN) { // No need to tweak existing names when creating zip file because there are none yet! return; } if (!file_exists($this->archivepathname)) { return; } if (!($fp = fopen($this->archivepathname, 'rb'))) { return; } if (!($filesize = filesize($this->archivepathname))) { return; } $centralend = self::zip_get_central_end($fp, $filesize); if ($centralend === false or $centralend['disk'] !== 0 or $centralend['disk_start'] !== 0 or $centralend['offset'] === 0xffffffff) { // Single disk archives only and o support for ZIP64, sorry. fclose($fp); return; } fseek($fp, $centralend['offset']); $data = fread($fp, $centralend['size']); $pos = 0; $files = array(); for ($i = 0; $i < $centralend['entries']; $i++) { $file = self::zip_parse_file_header($data, $centralend, $pos); if ($file === false) { // Wrong header, sorry. fclose($fp); return; } $files[] = $file; } fclose($fp); foreach ($files as $file) { $name = $file['name']; if (preg_match('/^[a-zA-Z0-9_\\-\\.]*$/', $file['name'])) { // No need to fix ASCII. $name = fix_utf8($name); } else { if (!($file['general'] & pow(2, 11))) { // First look for unicode name alternatives. $found = false; foreach ($file['extra'] as $extra) { if ($extra['id'] === 0x7075) { $data = unpack('cversion/Vcrc', substr($extra['data'], 0, 5)); if ($data['crc'] === crc32($name)) { $found = true; $name = substr($extra['data'], 5); } } } if (!$found and !empty($this->encoding) and $this->encoding !== 'utf-8') { // Try the encoding from open(). $newname = @core_text::convert($name, $this->encoding, 'utf-8'); $original = core_text::convert($newname, 'utf-8', $this->encoding); if ($original === $name) { $found = true; $name = $newname; } } if (!$found and $file['version'] === 0x315) { // This looks like OS X build in zipper. $newname = fix_utf8($name); if ($newname === $name) { $found = true; $name = $newname; } } if (!$found and $file['version'] === 0) { // This looks like our old borked Moodle 2.2 file. $newname = fix_utf8($name); if ($newname === $name) { $found = true; $name = $newname; } } if (!$found and $encoding = get_string('oldcharset', 'langconfig')) { // Last attempt - try the dos/unix encoding from current language. $windows = true; foreach ($file['extra'] as $extra) { // In Windows archivers do not usually set any extras with the exception of NTFS flag in WinZip/WinRar. $windows = false; if ($extra['id'] === 0xa) { $windows = true; break; } } if ($windows === true) { switch (strtoupper($encoding)) { case 'ISO-8859-1': $encoding = 'CP850'; break; case 'ISO-8859-2': $encoding = 'CP852'; break; case 'ISO-8859-4': $encoding = 'CP775'; break; case 'ISO-8859-5': $encoding = 'CP866'; break; case 'ISO-8859-6': $encoding = 'CP720'; break; case 'ISO-8859-7': $encoding = 'CP737'; break; case 'ISO-8859-8': $encoding = 'CP862'; break; case 'EUC-JP': case 'UTF-8': if ($winchar = get_string('localewincharset', 'langconfig')) { // Most probably works only for zh_cn, // if there are more problems we could add zipcharset to langconfig files. $encoding = $winchar; } break; } } $newname = @core_text::convert($name, $encoding, 'utf-8'); $original = core_text::convert($newname, 'utf-8', $encoding); if ($original === $name) { $name = $newname; } } } } $name = str_replace('\\', '/', $name); // no MS \ separators $name = clean_param($name, PARAM_PATH); // only safe chars $name = ltrim($name, '/'); // no leading slash if (function_exists('normalizer_normalize')) { $name = normalizer_normalize($name, Normalizer::FORM_C); } $this->namelookup[$file['name']] = $name; } }
/** * Parse this content * * @global object * @global object * @param string $content passed by ref for memory reasons, unset after return * @param string $encoding content encoding * @param string $delimiter_name separator (comma, semicolon, colon, cfg) * @param string $column_validation name of function for columns validation, must have one param $columns * @param string $enclosure field wrapper. One character only. * @return bool false if error, count of data lines if ok; use get_error() to get error string */ function load_csv_content(&$content, $encoding, $delimiter_name, $column_validation = null, $enclosure = '"') { global $USER, $CFG; $this->close(); $this->_error = null; $content = core_text::convert($content, $encoding, 'utf-8'); // remove Unicode BOM from first line $content = core_text::trim_utf8_bom($content); // Fix mac/dos newlines $content = preg_replace('!\\r\\n?!', "\n", $content); // Remove any spaces or new lines at the end of the file. if ($delimiter_name == 'tab') { // trim() by default removes tabs from the end of content which is undesirable in a tab separated file. $content = trim($content, chr(0x20) . chr(0xa) . chr(0xd) . chr(0x0) . chr(0xb)); } else { $content = trim($content); } $csv_delimiter = csv_import_reader::get_delimiter($delimiter_name); // $csv_encode = csv_import_reader::get_encoded_delimiter($delimiter_name); // Create a temporary file and store the csv file there, // do not try using fgetcsv() because there is nothing // to split rows properly - fgetcsv() itself can not do it. $tempfile = tempnam(make_temp_directory('/csvimport'), 'tmp'); if (!($fp = fopen($tempfile, 'w+b'))) { $this->_error = get_string('cannotsavedata', 'error'); @unlink($tempfile); return false; } fwrite($fp, $content); fseek($fp, 0); // Create an array to store the imported data for error checking. $columns = array(); // str_getcsv doesn't iterate through the csv data properly. It has // problems with line returns. while ($fgetdata = fgetcsv($fp, 0, $csv_delimiter, $enclosure)) { // Check to see if we have an empty line. if (count($fgetdata) == 1) { if ($fgetdata[0] !== null) { // The element has data. Add it to the array. $columns[] = $fgetdata; } } else { $columns[] = $fgetdata; } } $col_count = 0; // process header - list of columns if (!isset($columns[0])) { $this->_error = get_string('csvemptyfile', 'error'); fclose($fp); unlink($tempfile); return false; } else { $col_count = count($columns[0]); } // Column validation. if ($column_validation) { $result = $column_validation($columns[0]); if ($result !== true) { $this->_error = $result; fclose($fp); unlink($tempfile); return false; } } $this->_columns = $columns[0]; // cached columns // check to make sure that the data columns match up with the headers. foreach ($columns as $rowdata) { if (count($rowdata) !== $col_count) { $this->_error = get_string('csvweirdcolumns', 'error'); fclose($fp); unlink($tempfile); $this->cleanup(); return false; } } $filename = $CFG->tempdir . '/csvimport/' . $this->_type . '/' . $USER->id . '/' . $this->_iid; $filepointer = fopen($filename, "w"); // The information has been stored in csv format, as serialized data has issues // with special characters and line returns. $storedata = csv_export_writer::print_array($columns, ',', '"', true); fwrite($filepointer, $storedata); fclose($fp); unlink($tempfile); fclose($filepointer); $datacount = count($columns); return $datacount; }
/** * To be called from a page running under NTLM's * "Integrated Windows Authentication". * * If successful, it will set a special "cookie" (not an HTTP cookie!) * in cache_flags under the $this->pluginconfig/ntlmsess "plugin" and return true. * The "cookie" will be picked up by ntlmsso_finish() to complete the * process. * * On failure it will return false for the caller to display an appropriate * error message (probably saying that Integrated Windows Auth isn't enabled!) * * NOTE that this code will execute under the OS user credentials, * so we MUST avoid dealing with files -- such as session files. * (The caller should define('NO_MOODLE_COOKIES', true) before including config.php) * */ function ntlmsso_magic($sesskey) { if (isset($_SERVER['REMOTE_USER']) && !empty($_SERVER['REMOTE_USER'])) { // HTTP __headers__ seem to be sent in ISO-8859-1 encoding // (according to my reading of RFC-1945, RFC-2616 and RFC-2617 and // my local tests), so we need to convert the REMOTE_USER value // (i.e., what we got from the HTTP WWW-Authenticate header) into UTF-8 $username = core_text::convert($_SERVER['REMOTE_USER'], 'iso-8859-1', 'utf-8'); switch ($this->config->ntlmsso_type) { case 'ntlm': // The format is now configurable, so try to extract the username $username = $this->get_ntlm_remote_user($username); if (empty($username)) { return false; } break; case 'kerberos': // Format is username@DOMAIN $username = substr($username, 0, strpos($username, '@')); break; default: error_log($this->errorlogtag . get_string('ntlmsso_unknowntype', 'auth_ldap')); return false; // Should never happen! } $username = core_text::strtolower($username); // Compatibility hack set_cache_flag($this->pluginconfig . '/ntlmsess', $sesskey, $username, AUTH_NTLMTIMEOUT); return true; } return false; }
/** * Send an email to a specified user * * @param stdClass $user A {@link $USER} object * @param stdClass $from A {@link $USER} object * @param string $subject plain text subject line of the email * @param string $messagetext plain text version of the message * @param string $messagehtml complete html version of the message (optional) * @param string $attachment a file on the filesystem, either relative to $CFG->dataroot or a full path to a file in $CFG->tempdir * @param string $attachname the name of the file (extension indicates MIME) * @param bool $usetrueaddress determines whether $from email address should * be sent out. Will be overruled by user profile setting for maildisplay * @param string $replyto Email address to reply to * @param string $replytoname Name of reply to recipient * @param int $wordwrapwidth custom word wrap width, default 79 * @return bool Returns true if mail was sent OK and false if there was an error. */ function email_to_user($user, $from, $subject, $messagetext, $messagehtml = '', $attachment = '', $attachname = '', $usetrueaddress = true, $replyto = '', $replytoname = '', $wordwrapwidth = 79) { global $CFG; if (empty($user) or empty($user->id)) { debugging('Can not send email to null user', DEBUG_DEVELOPER); return false; } if (empty($user->email)) { debugging('Can not send email to user without email: ' . $user->id, DEBUG_DEVELOPER); return false; } if (!empty($user->deleted)) { debugging('Can not send email to deleted user: '******'BEHAT_SITE_RUNNING')) { // Fake email sending in behat. return true; } if (!empty($CFG->noemailever)) { // Hidden setting for development sites, set in config.php if needed. debugging('Not sending email due to $CFG->noemailever config setting', DEBUG_NORMAL); return true; } if (!empty($CFG->divertallemailsto)) { $subject = "[DIVERTED {$user->email}] {$subject}"; $user = clone $user; $user->email = $CFG->divertallemailsto; } // Skip mail to suspended users. if (isset($user->auth) && $user->auth == 'nologin' or isset($user->suspended) && $user->suspended) { return true; } if (!validate_email($user->email)) { // We can not send emails to invalid addresses - it might create security issue or confuse the mailer. debugging("email_to_user: User {$user->id} (" . fullname($user) . ") email ({$user->email}) is invalid! Not sending."); return false; } if (over_bounce_threshold($user)) { debugging("email_to_user: User {$user->id} (" . fullname($user) . ") is over bounce threshold! Not sending."); return false; } // TLD .invalid is specifically reserved for invalid domain names. // For More information, see {@link http://tools.ietf.org/html/rfc2606#section-2}. if (substr($user->email, -8) == '.invalid') { debugging("email_to_user: User {$user->id} (" . fullname($user) . ") email domain ({$user->email}) is invalid! Not sending."); return true; // This is not an error. } // If the user is a remote mnet user, parse the email text for URL to the // wwwroot and modify the url to direct the user's browser to login at their // home site (identity provider - idp) before hitting the link itself. if (is_mnet_remote_user($user)) { require_once $CFG->dirroot . '/mnet/lib.php'; $jumpurl = mnet_get_idp_jump_url($user); $callback = partial('mnet_sso_apply_indirection', $jumpurl); $messagetext = preg_replace_callback("%({$CFG->wwwroot}[^[:space:]]*)%", $callback, $messagetext); $messagehtml = preg_replace_callback("%href=[\"'`]({$CFG->wwwroot}[\\w_:\\?=#&@/;.~-]*)[\"'`]%", $callback, $messagehtml); } $mail = get_mailer(); if (!empty($mail->SMTPDebug)) { echo '<pre>' . "\n"; } $temprecipients = array(); $tempreplyto = array(); $supportuser = core_user::get_support_user(); // Make up an email address for handling bounces. if (!empty($CFG->handlebounces)) { $modargs = 'B' . base64_encode(pack('V', $user->id)) . substr(md5($user->email), 0, 16); $mail->Sender = generate_email_processing_address(0, $modargs); } else { $mail->Sender = $supportuser->email; } if (!empty($CFG->emailonlyfromnoreplyaddress)) { $usetrueaddress = false; if (empty($replyto) && $from->maildisplay) { $replyto = $from->email; $replytoname = fullname($from); } } if (is_string($from)) { // So we can pass whatever we want if there is need. $mail->From = $CFG->noreplyaddress; $mail->FromName = $from; } else { if ($usetrueaddress and $from->maildisplay) { $mail->From = $from->email; $mail->FromName = fullname($from); } else { $mail->From = $CFG->noreplyaddress; $mail->FromName = fullname($from); if (empty($replyto)) { $tempreplyto[] = array($CFG->noreplyaddress, get_string('noreplyname')); } } } if (!empty($replyto)) { $tempreplyto[] = array($replyto, $replytoname); } $mail->Subject = substr($subject, 0, 900); $temprecipients[] = array($user->email, fullname($user)); // Set word wrap. $mail->WordWrap = $wordwrapwidth; if (!empty($from->customheaders)) { // Add custom headers. if (is_array($from->customheaders)) { foreach ($from->customheaders as $customheader) { $mail->addCustomHeader($customheader); } } else { $mail->addCustomHeader($from->customheaders); } } if (!empty($from->priority)) { $mail->Priority = $from->priority; } if ($messagehtml && !empty($user->mailformat) && $user->mailformat == 1) { // Don't ever send HTML to users who don't want it. $mail->isHTML(true); $mail->Encoding = 'quoted-printable'; $mail->Body = $messagehtml; $mail->AltBody = "\n{$messagetext}\n"; } else { $mail->IsHTML(false); $mail->Body = "\n{$messagetext}\n"; } if ($attachment && $attachname) { if (preg_match("~\\.\\.~", $attachment)) { // Security check for ".." in dir path. $temprecipients[] = array($supportuser->email, fullname($supportuser, true)); $mail->addStringAttachment('Error in attachment. User attempted to attach a filename with a unsafe name.', 'error.txt', '8bit', 'text/plain'); } else { require_once $CFG->libdir . '/filelib.php'; $mimetype = mimeinfo('type', $attachname); $attachmentpath = $attachment; // Before doing the comparison, make sure that the paths are correct (Windows uses slashes in the other direction). $attachpath = str_replace('\\', '/', $attachmentpath); // Make sure both variables are normalised before comparing. $temppath = str_replace('\\', '/', $CFG->tempdir); // If the attachment is a full path to a file in the tempdir, use it as is, // otherwise assume it is a relative path from the dataroot (for backwards compatibility reasons). if (strpos($attachpath, realpath($temppath)) !== 0) { $attachmentpath = $CFG->dataroot . '/' . $attachmentpath; } $mail->addAttachment($attachmentpath, $attachname, 'base64', $mimetype); } } // Check if the email should be sent in an other charset then the default UTF-8. if (!empty($CFG->sitemailcharset) || !empty($CFG->allowusermailcharset)) { // Use the defined site mail charset or eventually the one preferred by the recipient. $charset = $CFG->sitemailcharset; if (!empty($CFG->allowusermailcharset)) { if ($useremailcharset = get_user_preferences('mailcharset', '0', $user->id)) { $charset = $useremailcharset; } } // Convert all the necessary strings if the charset is supported. $charsets = get_list_of_charsets(); unset($charsets['UTF-8']); if (in_array($charset, $charsets)) { $mail->CharSet = $charset; $mail->FromName = core_text::convert($mail->FromName, 'utf-8', strtolower($charset)); $mail->Subject = core_text::convert($mail->Subject, 'utf-8', strtolower($charset)); $mail->Body = core_text::convert($mail->Body, 'utf-8', strtolower($charset)); $mail->AltBody = core_text::convert($mail->AltBody, 'utf-8', strtolower($charset)); foreach ($temprecipients as $key => $values) { $temprecipients[$key][1] = core_text::convert($values[1], 'utf-8', strtolower($charset)); } foreach ($tempreplyto as $key => $values) { $tempreplyto[$key][1] = core_text::convert($values[1], 'utf-8', strtolower($charset)); } } } foreach ($temprecipients as $values) { $mail->addAddress($values[0], $values[1]); } foreach ($tempreplyto as $values) { $mail->addReplyTo($values[0], $values[1]); } if ($mail->send()) { set_send_count($user); if (!empty($mail->SMTPDebug)) { echo '</pre>'; } return true; } else { // Trigger event for failing to send email. $event = \core\event\email_failed::create(array('context' => context_system::instance(), 'userid' => $from->id, 'relateduserid' => $user->id, 'other' => array('subject' => $subject, 'message' => $messagetext, 'errorinfo' => $mail->ErrorInfo))); $event->trigger(); if (CLI_SCRIPT) { mtrace('Error: lib/moodlelib.php email_to_user(): ' . $mail->ErrorInfo); } if (!empty($mail->SMTPDebug)) { echo '</pre>'; } return false; } }
/** * Called when the user record is updated. * Modifies user in external database. It takes olduser (before changes) and newuser (after changes) * compares information saved modified information to external db. * * @param stdClass $olduser Userobject before modifications * @param stdClass $newuser Userobject new modified userobject * @return boolean result * */ function user_update($olduser, $newuser) { if (isset($olduser->username) and isset($newuser->username) and $olduser->username != $newuser->username) { error_log("ERROR:User renaming not allowed in ext db"); return false; } if (isset($olduser->auth) and $olduser->auth != $this->authtype) { return true; // Just change auth and skip update. } $curruser = $this->get_userinfo($olduser->username); if (empty($curruser)) { error_log("ERROR:User {$olduser->username} found in ext db"); return false; } $extusername = core_text::convert($olduser->username, 'utf-8', $this->config->extencoding); $authdb = $this->db_init(); $update = array(); foreach ($curruser as $key => $value) { if ($key == 'username') { continue; // Skip this. } if (empty($this->config->{"field_updateremote_{$key}"})) { continue; // Remote update not requested. } if (!isset($newuser->{$key})) { continue; } $nuvalue = $newuser->{$key}; if ($nuvalue != $value) { $update[] = $this->config->{"field_map_{$key}"} . "='" . $this->ext_addslashes(core_text::convert($nuvalue, 'utf-8', $this->config->extencoding)) . "'"; } } if (!empty($update)) { $authdb->Execute("UPDATE {$this->config->table}\n SET " . implode(',', $update) . "\n WHERE {$this->config->fielduser}='" . $this->ext_addslashes($extusername) . "'"); } $authdb->Close(); return true; }
function feedback_check_xml_utf8($text) { //find the encoding $searchpattern = '/^\\<\\?xml.+(encoding=\\"([a-z0-9-]*)\\").+\\?\\>/is'; if (!preg_match($searchpattern, $text, $match)) { return false; //no xml-file } //$match[0] = \<\? xml ... \?\> (without \) //$match[1] = encoding="...." //$match[2] = ISO-8859-1 or so on if (isset($match[0]) and !isset($match[1])) { //no encoding given. we assume utf-8 return $text; } //encoding is given in $match[2] if (isset($match[0]) and isset($match[1]) and isset($match[2])) { $enc = $match[2]; return core_text::convert($text, $enc); } }
/** * Tries to convert $localname into utf-8 * please note that it may fail really badly. * The resulting file name is cleaned. * * @param string $localname name of file in $this->encoding * @return string in utf-8 */ protected function unmangle_pathname($localname) { $result = str_replace('\\', '/', $localname); // no MS \ separators $result = ltrim($result, '/'); // no leading / if ($this->encoding !== 'utf-8') { $result = core_text::convert($result, $this->encoding, 'utf-8'); } return clean_param($result, PARAM_PATH); }
/** * Tests the static strtoupper. */ public function test_strtoupper() { $str = "Žluťoučký koníček"; $up = 'ŽLUŤOUČKÝ KONÍČEK'; $this->assertSame($up, core_text::strtoupper($str)); $iso2 = pack("H*", "ae6c75bb6f75e86bfd206b6f6eede8656b"); $this->assertSame(core_text::convert($up, 'utf-8', 'iso-8859-2'), core_text::strtoupper($iso2, 'iso-8859-2')); $win = pack("H*", "8e6c759d6f75e86bfd206b6f6eede8656b"); $this->assertSame(core_text::convert($up, 'utf-8', 'cp1250'), core_text::strtoupper($win, 'cp1250')); $str = '言語設定'; $this->assertSame($str, core_text::strtoupper($str)); $str = '简体中文'; $this->assertSame($str, core_text::strtoupper($str)); $str = pack("H*", "1b24423840386c405f446a1b2842"); // ISO-2022-JP $this->assertSame($str, core_text::strtoupper($str, 'ISO-2022-JP')); $str = pack("H*", "8cbe8cea90dd92e8"); // SHIFT-JIS $this->assertSame($str, core_text::strtoupper($str, 'SHIFT-JIS')); $str = pack("H*", "bcf2cce5d6d0cec4"); // GB2312 $this->assertSame($str, core_text::strtoupper($str, 'GB2312')); $str = pack("H*", "bcf2cce5d6d0cec4"); // GB18030 $this->assertSame($str, core_text::strtoupper($str, 'GB18030')); }
print_error('nomanualenrol', 'local_ltiprovider'); } // Transform to utf8 all the post and get data if (class_exists('textlib')) { $textlib = new textlib(); } else { try { // for older moodle instances $textlib = textlib_get_instance(); } catch (Exception $e) { // updated to use new core_text lib as required by Moodle 2.9 $textlib = new core_text(); } } foreach ($_POST as $key => $value) { $_POST[$key] = $textlib->convert($value, $tool->encoding); } foreach ($_GET as $key => $value) { $_GET[$key] = $textlib->convert($value, $tool->encoding); } // We need an username without extended chars // Later accounts add the ConsumerKey - we silently upgrade old accounts // Might want a flag for this -- Chuck $username = local_ltiprovider_create_username($context->info['oauth_consumer_key'], $context->info['user_id']); $dbuser = $DB->get_record('user', array('username' => $username)); if (!$dbuser) { $old_username = '******' . md5($context->getUserKey()); $dbuser = $DB->get_record('user', array('username' => $old_username)); if ($dbuser) { // Probably should log this $DB->set_field('user', 'username', $username, array('id' => $dbuser->id));
/** * Reads user information from ldap and returns it in array() * * Function should return all information available. If you are saving * this information to moodle user-table you should honor syncronization flags * * @param object $ldapauth the ldap authentication instance * @param string $username username * @param array $options an array with CLI input options * * @return mixed array with no magic quotes or false on error */ function local_ent_installer_get_userinfo($ldapauth, $username, $options = array()) { static $entattributes; // Load some cached static data. if (!isset($entattributes)) { // aggregate additional ent specific attributes that hold interesting information $configattribs = get_config('local_ent_installer', 'ent_userinfo_attributes'); if (empty($configattribs)) { $entattributes = array('ENTPersonFonctions', 'ENTPersonJointure', 'ENTEleveClasses', 'ENTEleveGroupes', 'ENTEleveTransport', 'ENTEleveRegime', 'ENTPersonProfils', 'objectGUID'); } else { $entattributes = explode(',', $configattribs); } } $extusername = core_text::convert($username, 'utf-8', $ldapauth->config->ldapencoding); $ldapconnection = $ldapauth->ldap_connect(); if (!($user_dn = $ldapauth->ldap_find_userdn($ldapconnection, $extusername))) { $ldapauth->ldap_close(); return false; } $search_attribs = array(); $attrmap = $ldapauth->ldap_attributes(); foreach ($attrmap as $key => $values) { if (!is_array($values)) { $values = array($values); } foreach ($values as $value) { if (!in_array($value, $search_attribs)) { array_push($search_attribs, $value); } } } foreach ($entattributes as $value) { if (!in_array($value, $search_attribs)) { array_push($search_attribs, $value); // Add attributes to $attrmap so they are pulled down into final user object. $attrmap[$value] = strtolower($value); } } if ($options['verbose']) { mtrace("Getting {$user_dn} for " . implode(',', $search_attribs)); } if (!($user_info_result = ldap_read($ldapconnection, $user_dn, '(objectClass=*)', $search_attribs))) { $ldapauth->ldap_close(); return false; } $user_entry = ldap_get_entries_moodle($ldapconnection, $user_info_result); if (empty($user_entry)) { $ldapauth->ldap_close(); return false; // Entry not found. } $result = array(); foreach ($attrmap as $key => $values) { if (!is_array($values)) { $values = array($values); } $ldapval = NULL; foreach ($values as $value) { $entry = array_change_key_case($user_entry[0], CASE_LOWER); if ($value == 'dn' || $value == 'distinguishedname') { $result[$key] = $user_dn; continue; } if (!array_key_exists($value, $entry)) { if ($options['verbose']) { mtrace("Requested value {$value} but missing in record"); } continue; // wrong data mapping! } if ($value == 'objectguid') { if (strlen($entry[$value][0]) == 16) { $tmp = bin2hex($entry[$value][0]); $t = $tmp[6] . $tmp[7] . $tmp[4] . $tmp[5] . $tmp[2] . $tmp[3] . $tmp[0] . $tmp[1] . '-'; $t .= $tmp[10] . $tmp[11] . $tmp[8] . $tmp[9] . '-'; $t .= $tmp[14] . $tmp[15] . $tmp[12] . $tmp[13] . '-'; $t .= substr($tmp, 16, 4) . '-'; $t .= substr($tmp, 20); $objectguid = $t; } $newval = $objectguid; } else { if ($value == 'entelevegroupes' && is_array($entry[$value])) { $newval = array(); foreach ($entry[$value] as $subkey => $subvalue) { if ($subkey !== 'count') { $newval[] = core_text::convert($subvalue, $ldapauth->config->ldapencoding, 'utf-8'); } } } else { if (is_array($entry[$value])) { $newval = core_text::convert($entry[$value][0], $ldapauth->config->ldapencoding, 'utf-8'); } else { $newval = core_text::convert($entry[$value], $ldapauth->config->ldapencoding, 'utf-8'); } } } if (!empty($newval)) { // Favour ldap entries that are set. $ldapval = $newval; } } if (!is_null($ldapval)) { $result[$key] = $ldapval; } } $ldapauth->ldap_close(); return $result; }
public function test_sync() { global $CFG, $DB; $this->resetAfterTest(); /** @var enrol_flatfile_plugin $flatfileplugin */ $flatfileplugin = enrol_get_plugin('flatfile'); /** @var enrol_manual_plugin $manualplugin */ $manualplugin = enrol_get_plugin('manual'); $this->assertNotEmpty($manualplugin); $trace = new null_progress_trace(); $this->enable_plugin(); $file = "{$CFG->dataroot}/enrol.txt"; $studentrole = $DB->get_record('role', array('shortname' => 'student')); $this->assertNotEmpty($studentrole); $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); $this->assertNotEmpty($teacherrole); $managerrole = $DB->get_record('role', array('shortname' => 'manager')); $this->assertNotEmpty($managerrole); $user1 = $this->getDataGenerator()->create_user(array('idnumber' => 'u1')); $user2 = $this->getDataGenerator()->create_user(array('idnumber' => 'u2')); $user3 = $this->getDataGenerator()->create_user(array('idnumber' => 'u3')); $user4 = $this->getDataGenerator()->create_user(array('idnumber' => 'čtvrtý')); $user5 = $this->getDataGenerator()->create_user(array('idnumber' => 'u5')); $user6 = $this->getDataGenerator()->create_user(array('idnumber' => 'u6')); $user7 = $this->getDataGenerator()->create_user(array('idnumber' => '')); $course1 = $this->getDataGenerator()->create_course(array('idnumber' => 'c1')); $course2 = $this->getDataGenerator()->create_course(array('idnumber' => 'c2')); $course3 = $this->getDataGenerator()->create_course(array('idnumber' => 'c3')); $context1 = context_course::instance($course1->id); $context2 = context_course::instance($course2->id); $context3 = context_course::instance($course3->id); $maninstance1 = $DB->get_record('enrol', array('courseid' => $course1->id, 'enrol' => 'manual'), '*', MUST_EXIST); $maninstance2 = $DB->get_record('enrol', array('courseid' => $course2->id, 'enrol' => 'manual'), '*', MUST_EXIST); $maninstance3 = $DB->get_record('enrol', array('courseid' => $course3->id, 'enrol' => 'manual'), '*', MUST_EXIST); // Rename teacher role. $flatfileplugin->set_config('map_' . $teacherrole->id, 'ucitel'); // Disable manager role. $flatfileplugin->set_config('map_' . $managerrole->id, ''); // Set file location. $flatfileplugin->set_config('location', $file); $now = time(); $before = $now - 60; $future = $now + 60 * 60 * 5; $farfuture = $now + 60 * 60 * 24 * 5; // Test add action. $data = "'add','student','u1','c1'\n\n \"add\" , \"ucitel\", u2 , c2\n add,manager,u3,c1\n add,student,čtvrtý,c2,{$before}\n add,student,u5,c1,0,0,1\n add,student,u5,c2,20,10\n add,student,u6,c1,0,{$future}\n add,student,u6,c2,{$future},0\n add,student,u6,c3,{$future},{$farfuture}\n add,student,,c2"; file_put_contents($file, $data); $this->assertEquals(0, $DB->count_records('user_enrolments')); $this->assertEquals(0, $DB->count_records('role_assignments')); $this->assertEquals(0, $DB->count_records('enrol_flatfile')); $this->assertTrue(file_exists($file)); $flatfileplugin->sync($trace); $this->assertFalse(file_exists($file)); $this->assertEquals(4, $DB->count_records('user_enrolments')); $this->assertEquals(4, $DB->count_records('role_assignments')); $this->assertTrue($DB->record_exists('role_assignments', array('contextid' => $context1->id, 'userid' => $user1->id, 'roleid' => $studentrole->id, 'component' => 'enrol_flatfile'))); $this->assertTrue($DB->record_exists('role_assignments', array('contextid' => $context2->id, 'userid' => $user2->id, 'roleid' => $teacherrole->id, 'component' => 'enrol_flatfile'))); $this->assertTrue($DB->record_exists('role_assignments', array('contextid' => $context2->id, 'userid' => $user4->id, 'roleid' => $studentrole->id, 'component' => 'enrol_flatfile'))); $this->assertTrue($DB->record_exists('role_assignments', array('contextid' => $context1->id, 'userid' => $user6->id, 'roleid' => $studentrole->id, 'component' => 'enrol_flatfile'))); // Test buffer. $this->assertEquals(2, $DB->count_records('enrol_flatfile')); $flatfileplugin->sync($trace); $this->assertEquals(2, $DB->count_records('enrol_flatfile')); $this->assertEquals(4, $DB->count_records('user_enrolments')); $this->assertEquals(4, $DB->count_records('role_assignments')); $DB->set_field('enrol_flatfile', 'timestart', time() - 60, array('timestart' => $future, 'timeend' => 0)); $flatfileplugin->sync($trace); $this->assertEquals(1, $DB->count_records('enrol_flatfile')); $this->assertEquals(5, $DB->count_records('user_enrolments')); $this->assertEquals(5, $DB->count_records('role_assignments')); $this->assertTrue($DB->record_exists('role_assignments', array('contextid' => $context2->id, 'userid' => $user6->id, 'roleid' => $studentrole->id, 'component' => 'enrol_flatfile'))); $this->assertTrue($DB->record_exists('enrol_flatfile', array('userid' => $user6->id, 'roleid' => $studentrole->id, 'timeend' => $farfuture))); // Test encoding. $data = "add;student;čtvrtý;c3"; $data = core_text::convert($data, 'utf-8', 'iso-8859-2'); file_put_contents($file, $data); $flatfileplugin->set_config('encoding', 'iso-8859-2'); $flatfileplugin->sync($trace); $this->assertEquals(6, $DB->count_records('user_enrolments')); $this->assertEquals(6, $DB->count_records('role_assignments')); $this->assertTrue($DB->record_exists('role_assignments', array('contextid' => $context3->id, 'userid' => $user4->id, 'roleid' => $studentrole->id, 'component' => 'enrol_flatfile'))); $flatfileplugin->set_config('encoding', 'UTF-8'); // Test unenrolling purges buffer. $manualplugin->enrol_user($maninstance1, $user1->id, $teacherrole->id); $manualplugin->enrol_user($maninstance3, $user5->id, $teacherrole->id); $this->assertEquals(8, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(1, $DB->count_records('enrol_flatfile')); $this->assertTrue($DB->record_exists('role_assignments', array('contextid' => $context1->id, 'userid' => $user1->id, 'roleid' => $teacherrole->id))); $flatfileplugin->set_config('unenrolaction', ENROL_EXT_REMOVED_KEEP); $data = "del,student,u1,c1\ndel,teacher,u6,c3"; file_put_contents($file, $data); $flatfileplugin->sync($trace); $this->assertEquals(8, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(1, $DB->count_records('enrol_flatfile')); $data = "del,student,u6,c3"; file_put_contents($file, $data); $flatfileplugin->sync($trace); $this->assertEquals(8, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(0, $DB->count_records('enrol_flatfile')); $flatfileplugin->set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES); $data = "\n del,student,u1,c1\n del,grrr,u5,c1\n del,guest,u5,c2\n del,student,u6,c2\n del,ucitel,u5,c3"; file_put_contents($file, $data); $this->assertTrue($DB->record_exists('role_assignments', array('contextid' => $context1->id, 'userid' => $user1->id, 'roleid' => $studentrole->id, 'component' => 'enrol_flatfile'))); $this->assertTrue($DB->record_exists('role_assignments', array('contextid' => $context2->id, 'userid' => $user6->id, 'roleid' => $studentrole->id))); $this->assertTrue($DB->record_exists('role_assignments', array('contextid' => $context3->id, 'userid' => $user5->id, 'roleid' => $teacherrole->id))); $flatfileplugin->sync($trace); $this->assertEquals(8, $DB->count_records('user_enrolments')); $this->assertEquals(5, $DB->count_records('role_assignments')); $this->assertFalse($DB->record_exists('role_assignments', array('contextid' => $context1->id, 'userid' => $user1->id, 'roleid' => $studentrole->id, 'component' => 'enrol_flatfile'))); $this->assertTrue($DB->record_exists('role_assignments', array('contextid' => $context1->id, 'userid' => $user1->id, 'roleid' => $teacherrole->id))); $this->assertFalse($DB->record_exists('role_assignments', array('contextid' => $context2->id, 'userid' => $user6->id, 'roleid' => $studentrole->id))); $this->assertFalse($DB->record_exists('role_assignments', array('contextid' => $context3->id, 'userid' => $user5->id, 'roleid' => $teacherrole->id))); $flatfileplugin->set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL); $manualplugin->enrol_user($maninstance3, $user5->id, $teacherrole->id); $data = "\n add,student,u1,c1\n add,student,u6,c2"; file_put_contents($file, $data); $flatfileplugin->sync($trace); $this->assertEquals(8, $DB->count_records('user_enrolments')); $this->assertEquals(8, $DB->count_records('role_assignments')); $this->assertEquals(0, $DB->count_records('enrol_flatfile')); $this->assertTrue($DB->record_exists('role_assignments', array('contextid' => $context1->id, 'userid' => $user1->id, 'roleid' => $studentrole->id, 'component' => 'enrol_flatfile'))); $this->assertTrue($DB->record_exists('role_assignments', array('contextid' => $context2->id, 'userid' => $user6->id, 'roleid' => $studentrole->id))); $this->assertTrue($DB->record_exists('role_assignments', array('contextid' => $context3->id, 'userid' => $user5->id, 'roleid' => $teacherrole->id))); $this->assertTrue($DB->record_exists('user_enrolments', array('userid' => $user5->id, 'enrolid' => $maninstance3->id))); $this->assertTrue($DB->record_exists('user_enrolments', array('userid' => $user1->id, 'enrolid' => $maninstance1->id))); $data = "\n del,student,u1,c1\n del,grrr,u5,c1\n del,guest,u5,c2\n del,student,u6,c2\n del,ucitel,u5,c3"; file_put_contents($file, $data); $flatfileplugin->sync($trace); $this->assertEquals(5, $DB->count_records('user_enrolments')); $this->assertEquals(5, $DB->count_records('role_assignments')); $this->assertFalse($DB->record_exists('role_assignments', array('contextid' => $context1->id, 'userid' => $user1->id, 'roleid' => $studentrole->id, 'component' => 'enrol_flatfile'))); $this->assertTrue($DB->record_exists('role_assignments', array('contextid' => $context1->id, 'userid' => $user1->id, 'roleid' => $teacherrole->id))); $this->assertFalse($DB->record_exists('role_assignments', array('contextid' => $context2->id, 'userid' => $user6->id, 'roleid' => $studentrole->id))); $this->assertFalse($DB->record_exists('role_assignments', array('contextid' => $context3->id, 'userid' => $user5->id, 'roleid' => $teacherrole->id))); $this->assertFalse($DB->record_exists('user_enrolments', array('userid' => $user5->id, 'enrolid' => $maninstance3->id))); $this->assertTrue($DB->record_exists('user_enrolments', array('userid' => $user1->id, 'enrolid' => $maninstance1->id))); }
/** * * returns the distinct values of the target LDAP attribute * these will be the idnumbers of the synched Moodle cohorts * @returns array of string */ function get_attribute_distinct_values() { //return array ('affiliate','retired','student','faculty','staff','employee','affiliate','member','alum','emeritus','researcher'); global $CFG, $DB; // only these cohorts will be synched if (!empty($this->config->cohort_synching_ldap_attribute_idnumbers)) { return explode(',', $this->config->cohort_synching_ldap_attribute_idnumbers); } //build a filter to fetch all users having something in the target LDAP attribute $filter = '(&(' . $this->config->user_attribute . '=*)' . $this->config->objectclass . ')'; $filter = '(&' . $filter . '(' . $this->config->cohort_synching_ldap_attribute_attribute . '=*))'; if ($CFG->debug_ldap_groupes) { pp_print_object('looking for ', $filter); } $ldapconnection = $this->ldap_connect(); $contexts = explode(';', $this->config->contexts); if (!empty($this->config->create_context)) { array_push($contexts, $this->config->create_context); } $matchings = array(); foreach ($contexts as $context) { $context = trim($context); if (empty($context)) { continue; } if ($this->config->search_sub) { // Use ldap_search to find first user from subtree $ldap_result = ldap_search($ldapconnection, $context, $filter, array($this->config->cohort_synching_ldap_attribute_attribute)); } else { // Search only in this context $ldap_result = ldap_list($ldapconnection, $context, $filter, array($this->config->cohort_synching_ldap_attribute_attribute)); } if (!$ldap_result) { continue; } // this API function returns all attributes as an array // wether they are single or multiple $users = ldap_get_entries_moodle($ldapconnection, $ldap_result); // Add found DISTINCT values to list for ($i = 0; $i < count($users); $i++) { $count = $users[$i][$this->config->cohort_synching_ldap_attribute_attribute]['count']; for ($j = 0; $j < $count; $j++) { $value = core_text::convert($users[$i][$this->config->cohort_synching_ldap_attribute_attribute][$j], $this->config->ldapencoding, 'utf-8'); if (!in_array($value, $matchings)) { array_push($matchings, $value); } } } } $this->ldap_close(); return $matchings; }
public function sanitize($data, $type, $base = '') { $data = trim($data); if ($data === '') { return ''; } if ($type & SIMPLEPIE_CONSTRUCT_BASE64) { $data = base64_decode($data); } if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML) { if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\\/[A-Za-z][^\\x09\\x0A\\x0B\\x0C\\x0D\\x20\\x2F\\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data)) { $type |= SIMPLEPIE_CONSTRUCT_HTML; } else { $type |= SIMPLEPIE_CONSTRUCT_TEXT; } } if ($type & SIMPLEPIE_CONSTRUCT_IRI) { $absolute = $this->registry->call('Misc', 'absolutize_url', array($data, $base)); if ($absolute !== false) { $data = $absolute; } $data = clean_param($data, PARAM_URL); } if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI)) { $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8'); } $data = purify_html($data); if ($this->remove_div) { $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data); $data = preg_replace('/<\\/div>$/', '', $data); } else { $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data); } if ($this->output_encoding !== 'UTF-8') { core_text::convert($data, 'UTF-8', $this->output_encoding); } return $data; }
/** * Process the messagedata and part data to extract the content of this part. * * @param \Horde_Imap_Client_Data_Fetch $messagedata The structure and part of the message body * @param \Horde_Mime_Part $partdata The part data * @param string $part The part ID * @return string */ private function process_message_part_body($messagedata, $partdata, $part) { // This is a content section for the main body. // Get the string version of it. $content = $messagedata->getBodyPart($part); if (!$messagedata->getBodyPartDecode($part)) { // Decode the content. $partdata->setContents($content); $content = $partdata->getContents(); } // Convert the text from the current encoding to UTF8. $content = \core_text::convert($content, $partdata->getCharset()); // Fix any invalid UTF8 characters. // Note: XSS cleaning is not the responsibility of this code. It occurs immediately before display when // format_text is called. $content = clean_param($content, PARAM_RAW); return $content; }
/** * Returns location information * @param string $ip * @return array */ function iplookup_find_location($ip) { global $CFG; $info = array('city' => null, 'country' => null, 'longitude' => null, 'latitude' => null, 'error' => null, 'note' => '', 'title' => array()); if (!empty($CFG->geoipfile) and file_exists($CFG->geoipfile)) { require_once 'Net/GeoIP.php'; $geoip = Net_GeoIP::getInstance($CFG->geoipfile, Net_GeoIP::STANDARD); $location = $geoip->lookupLocation($ip); $geoip->close(); if (empty($location)) { $info['error'] = get_string('iplookupfailed', 'error', $ip); return $info; } if (!empty($location->city)) { $info['city'] = core_text::convert($location->city, 'iso-8859-1', 'utf-8'); $info['title'][] = $info['city']; } if (!empty($location->countryCode)) { $countries = get_string_manager()->get_list_of_countries(true); if (isset($countries[$location->countryCode])) { // prefer our localized country names $info['country'] = $countries[$location->countryCode]; } else { $info['country'] = $location->countryName; } $info['title'][] = $info['country']; } else { if (!empty($location->countryName)) { $info['country'] = $location->countryName; $info['title'][] = $info['country']; } } $info['longitude'] = $location->longitude; $info['latitude'] = $location->latitude; $info['note'] = get_string('iplookupmaxmindnote', 'admin'); return $info; } else { require_once $CFG->libdir . '/filelib.php'; $ipdata = download_file_content('http://www.geoplugin.net/json.gp?ip=' . $ip); if ($ipdata) { $ipdata = preg_replace('/^geoPlugin\\((.*)\\)\\s*$/s', '$1', $ipdata); $ipdata = json_decode($ipdata, true); } if (!is_array($ipdata)) { $info['error'] = get_string('cannotgeoplugin', 'error'); return $info; } $info['latitude'] = (double) $ipdata['geoplugin_latitude']; $info['longitude'] = (double) $ipdata['geoplugin_longitude']; $info['city'] = s($ipdata['geoplugin_city']); $countrycode = $ipdata['geoplugin_countryCode']; $countries = get_string_manager()->get_list_of_countries(true); if (isset($countries[$countrycode])) { // prefer our localized country names $info['country'] = $countries[$countrycode]; } else { $info['country'] = s($ipdata['geoplugin_countryName']); } $info['note'] = get_string('iplookupgeoplugin', 'admin'); $info['title'][] = $info['city']; $info['title'][] = $info['country']; return $info; } }
/** * Send an email to a specified user * * @param stdClass $user A {@link $USER} object * @param stdClass $from A {@link $USER} object * @param string $subject plain text subject line of the email * @param string $messagetext plain text version of the message * @param string $messagehtml complete html version of the message (optional) * @param string $attachment a file on the filesystem, relative to $CFG->dataroot * @param string $attachname the name of the file (extension indicates MIME) * @param bool $usetrueaddress determines whether $from email address should * be sent out. Will be overruled by user profile setting for maildisplay * @param string $replyto Email address to reply to * @param string $replytoname Name of reply to recipient * @param int $wordwrapwidth custom word wrap width, default 79 * @return bool Returns true if mail was sent OK and false if there was an error. */ function email_to_user($user, $from, $subject, $messagetext, $messagehtml = '', $attachment = '', $attachname = '', $usetrueaddress = true, $replyto = '', $replytoname = '', $wordwrapwidth = 79) { global $CFG; if (empty($user) or empty($user->id)) { debugging('Can not send email to null user', DEBUG_DEVELOPER); return false; } if (empty($user->email)) { debugging('Can not send email to user without email: ' . $user->id, DEBUG_DEVELOPER); return false; } if (!empty($user->deleted)) { debugging('Can not send email to deleted user: '******'Not sending email due to $CFG->noemailever config setting', DEBUG_NORMAL); return true; } if (!empty($CFG->divertallemailsto)) { $subject = "[DIVERTED {$user->email}] {$subject}"; $user = clone $user; $user->email = $CFG->divertallemailsto; } // Skip mail to suspended users. if (isset($user->auth) && $user->auth == 'nologin' or isset($user->suspended) && $user->suspended) { return true; } if (!validate_email($user->email)) { // We can not send emails to invalid addresses - it might create security issue or confuse the mailer. $invalidemail = "User {$user->id} (" . fullname($user) . ") email ({$user->email}) is invalid! Not sending."; error_log($invalidemail); if (CLI_SCRIPT) { mtrace('Error: lib/moodlelib.php email_to_user(): ' . $invalidemail); } return false; } if (over_bounce_threshold($user)) { $bouncemsg = "User {$user->id} (" . fullname($user) . ") is over bounce threshold! Not sending."; error_log($bouncemsg); if (CLI_SCRIPT) { mtrace('Error: lib/moodlelib.php email_to_user(): ' . $bouncemsg); } return false; } // If the user is a remote mnet user, parse the email text for URL to the // wwwroot and modify the url to direct the user's browser to login at their // home site (identity provider - idp) before hitting the link itself. if (is_mnet_remote_user($user)) { require_once $CFG->dirroot . '/mnet/lib.php'; $jumpurl = mnet_get_idp_jump_url($user); $callback = partial('mnet_sso_apply_indirection', $jumpurl); $messagetext = preg_replace_callback("%({$CFG->wwwroot}[^[:space:]]*)%", $callback, $messagetext); $messagehtml = preg_replace_callback("%href=[\"'`]({$CFG->wwwroot}[\\w_:\\?=#&@/;.~-]*)[\"'`]%", $callback, $messagehtml); } $mail = get_mailer(); if (!empty($mail->SMTPDebug)) { echo '<pre>' . "\n"; } $temprecipients = array(); $tempreplyto = array(); $supportuser = core_user::get_support_user(); // Make up an email address for handling bounces. if (!empty($CFG->handlebounces)) { $modargs = 'B' . base64_encode(pack('V', $user->id)) . substr(md5($user->email), 0, 16); $mail->Sender = generate_email_processing_address(0, $modargs); } else { $mail->Sender = $supportuser->email; } if (is_string($from)) { // So we can pass whatever we want if there is need. $mail->From = $CFG->noreplyaddress; $mail->FromName = $from; } else { if ($usetrueaddress and $from->maildisplay) { $mail->From = $from->email; $mail->FromName = fullname($from); } else { $mail->From = $CFG->noreplyaddress; $mail->FromName = fullname($from); if (empty($replyto)) { $tempreplyto[] = array($CFG->noreplyaddress, get_string('noreplyname')); } } } if (!empty($replyto)) { $tempreplyto[] = array($replyto, $replytoname); } $mail->Subject = substr($subject, 0, 900); $temprecipients[] = array($user->email, fullname($user)); // Set word wrap. $mail->WordWrap = $wordwrapwidth; if (!empty($from->customheaders)) { // Add custom headers. if (is_array($from->customheaders)) { foreach ($from->customheaders as $customheader) { $mail->addCustomHeader($customheader); } } else { $mail->addCustomHeader($from->customheaders); } } if (!empty($from->priority)) { $mail->Priority = $from->priority; } if ($messagehtml && !empty($user->mailformat) && $user->mailformat == 1) { // Don't ever send HTML to users who don't want it. $mail->isHTML(true); $mail->Encoding = 'quoted-printable'; $mail->Body = $messagehtml; $mail->AltBody = "\n{$messagetext}\n"; } else { $mail->IsHTML(false); $mail->Body = "\n{$messagetext}\n"; } if ($attachment && $attachname) { if (preg_match("~\\.\\.~", $attachment)) { // Security check for ".." in dir path. $temprecipients[] = array($supportuser->email, fullname($supportuser, true)); $mail->addStringAttachment('Error in attachment. User attempted to attach a filename with a unsafe name.', 'error.txt', '8bit', 'text/plain'); } else { require_once $CFG->libdir . '/filelib.php'; $mimetype = mimeinfo('type', $attachname); $mail->addAttachment($CFG->dataroot . '/' . $attachment, $attachname, 'base64', $mimetype); } } // Check if the email should be sent in an other charset then the default UTF-8. if (!empty($CFG->sitemailcharset) || !empty($CFG->allowusermailcharset)) { // Use the defined site mail charset or eventually the one preferred by the recipient. $charset = $CFG->sitemailcharset; if (!empty($CFG->allowusermailcharset)) { if ($useremailcharset = get_user_preferences('mailcharset', '0', $user->id)) { $charset = $useremailcharset; } } // Convert all the necessary strings if the charset is supported. $charsets = get_list_of_charsets(); unset($charsets['UTF-8']); if (in_array($charset, $charsets)) { $mail->CharSet = $charset; $mail->FromName = core_text::convert($mail->FromName, 'utf-8', strtolower($charset)); $mail->Subject = core_text::convert($mail->Subject, 'utf-8', strtolower($charset)); $mail->Body = core_text::convert($mail->Body, 'utf-8', strtolower($charset)); $mail->AltBody = core_text::convert($mail->AltBody, 'utf-8', strtolower($charset)); foreach ($temprecipients as $key => $values) { $temprecipients[$key][1] = core_text::convert($values[1], 'utf-8', strtolower($charset)); } foreach ($tempreplyto as $key => $values) { $tempreplyto[$key][1] = core_text::convert($values[1], 'utf-8', strtolower($charset)); } } } foreach ($temprecipients as $values) { $mail->addAddress($values[0], $values[1]); } foreach ($tempreplyto as $values) { $mail->addReplyTo($values[0], $values[1]); } if ($mail->send()) { set_send_count($user); if (!empty($mail->SMTPDebug)) { echo '</pre>'; } return true; } else { add_to_log(SITEID, 'library', 'mailer', qualified_me(), 'ERROR: ' . $mail->ErrorInfo); if (CLI_SCRIPT) { mtrace('Error: lib/moodlelib.php email_to_user(): ' . $mail->ErrorInfo); } if (!empty($mail->SMTPDebug)) { echo '</pre>'; } return false; } }
protected function db_decode($text) { $dbenc = $this->get_config('dbencoding'); if (empty($dbenc) or $dbenc == 'utf-8') { return $text; } if (is_array($text)) { foreach ($text as $k => $value) { $text[$k] = $this->db_decode($value); } return $text; } else { return core_text::convert($text, $dbenc, 'utf-8'); } }
/** * Returns true if user should be coursecreator. * * @param mixed $username username (without system magic quotes) * @return boolean result */ function iscreator($username) { if (empty($this->config->host_url) or empty($this->config->attrcreators) && empty($this->config->groupecreators) or empty($this->config->memberattribute)) { return false; } $extusername = core_text::convert($username, 'utf-8', $this->config->ldapencoding); // Test for group creator if (!empty($this->config->groupecreators)) { $ldapconnection = $this->ldap_connect(); if ($this->config->memberattribute_isdn) { if (!($userid = $this->ldap_find_userdn($ldapconnection, $extusername))) { return false; } } else { $userid = $extusername; } $group_dns = explode(';', $this->config->groupecreators); if (ldap_isgroupmember($ldapconnection, $userid, $group_dns, $this->config->memberattribute)) { return true; } } // Build filter for attrcreator if (!empty($this->config->attrcreators)) { $attrs = explode(';', $this->config->attrcreators); $filter = '(& (' . $this->config->user_attribute . "={$username})(|"; foreach ($attrs as $attr) { if (strpos($attr, '=')) { $filter .= "({$attr})"; } else { $filter .= '(' . $this->config->memberattribute . "={$attr})"; } } $filter .= '))'; // Search $result = $this->ldap_get_userlist($filter); if (count($result) != 0) { return true; } } return false; }
/** * Convert some html content to utf8, getting original encoding from html headers * * @param string $html html content to convert * @return string html content converted to utf8 */ function toolbook_importhtml_fix_encoding($html) { if (preg_match('/<head[^>]*>(.+)<\\/head>/is', $html, $matches)) { $head = $matches[1]; if (preg_match('/charset=([^"]+)/is', $head, $matches)) { $enc = $matches[1]; return core_text::convert($html, $enc, 'utf-8'); } } return iconv('UTF-8', 'UTF-8//IGNORE', $html); }
/** * Return multidimensional array with details of user courses (at * least dn and idnumber). * * @param string $memberuid user idnumber (without magic quotes). * @param object role is a record from the mdl_role table. * @return array */ protected function find_ext_enrolments($memberuid, $role) { global $CFG; require_once $CFG->libdir . '/ldaplib.php'; if (empty($memberuid)) { // No "idnumber" stored for this user, so no LDAP enrolments return array(); } $ldap_contexts = trim($this->get_config('contexts_role' . $role->id)); if (empty($ldap_contexts)) { // No role contexts, so no LDAP enrolments return array(); } $extmemberuid = core_text::convert($memberuid, 'utf-8', $this->get_config('ldapencoding')); if ($this->get_config('memberattribute_isdn')) { if (!($extmemberuid = $this->ldap_find_userdn($extmemberuid))) { return array(); } } $ldap_search_pattern = ''; if ($this->get_config('nested_groups')) { $usergroups = $this->ldap_find_user_groups($extmemberuid); if (count($usergroups) > 0) { foreach ($usergroups as $group) { $ldap_search_pattern .= '(' . $this->get_config('memberattribute_role' . $role->id) . '=' . $group . ')'; } } } // Default return value $courses = array(); // Get all the fields we will want for the potential course creation // as they are light. don't get membership -- potentially a lot of data. $ldap_fields_wanted = array('dn', $this->get_config('course_idnumber')); $fullname = $this->get_config('course_fullname'); $shortname = $this->get_config('course_shortname'); $summary = $this->get_config('course_summary'); if (isset($fullname)) { array_push($ldap_fields_wanted, $fullname); } if (isset($shortname)) { array_push($ldap_fields_wanted, $shortname); } if (isset($summary)) { array_push($ldap_fields_wanted, $summary); } // Define the search pattern if (empty($ldap_search_pattern)) { $ldap_search_pattern = '(' . $this->get_config('memberattribute_role' . $role->id) . '=' . ldap_filter_addslashes($extmemberuid) . ')'; } else { $ldap_search_pattern = '(|' . $ldap_search_pattern . '(' . $this->get_config('memberattribute_role' . $role->id) . '=' . ldap_filter_addslashes($extmemberuid) . ')' . ')'; } $ldap_search_pattern = '(&' . $this->get_config('objectclass') . $ldap_search_pattern . ')'; // Get all contexts and look for first matching user $ldap_contexts = explode(';', $ldap_contexts); $ldap_pagedresults = ldap_paged_results_supported($this->get_config('ldap_version')); foreach ($ldap_contexts as $context) { $context = trim($context); if (empty($context)) { continue; } $ldap_cookie = ''; $flat_records = array(); do { if ($ldap_pagedresults) { ldap_control_paged_result($this->ldapconnection, $this->config->pagesize, true, $ldap_cookie); } if ($this->get_config('course_search_sub')) { // Use ldap_search to find first user from subtree $ldap_result = @ldap_search($this->ldapconnection, $context, $ldap_search_pattern, $ldap_fields_wanted); } else { // Search only in this context $ldap_result = @ldap_list($this->ldapconnection, $context, $ldap_search_pattern, $ldap_fields_wanted); } if (!$ldap_result) { continue; } if ($ldap_pagedresults) { ldap_control_paged_result_response($this->ldapconnection, $ldap_result, $ldap_cookie); } // Check and push results. ldap_get_entries() already // lowercases the attribute index, so there's no need to // use array_change_key_case() later. $records = ldap_get_entries($this->ldapconnection, $ldap_result); // LDAP libraries return an odd array, really. Fix it. for ($c = 0; $c < $records['count']; $c++) { array_push($flat_records, $records[$c]); } // Free some mem unset($records); } while ($ldap_pagedresults && !empty($ldap_cookie)); // If LDAP paged results were used, the current connection must be completely // closed and a new one created, to work without paged results from here on. if ($ldap_pagedresults) { $this->ldap_close(); $this->ldap_connect(); } if (count($flat_records)) { $courses = array_merge($courses, $flat_records); } } return $courses; }
public function readquestions($lines) { $webctnumberregex = '[+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)((e|E|\\*10\\*\\*)([+-]?[0-9]+|\\([+-]?[0-9]+\\)))?'; $questions = array(); $warnings = array(); $webctoptions = array(); $ignorerestofquestion = false; $nlinecounter = 0; $nquestionstartline = 0; $bishtmltext = false; $lines[] = ":EOF:"; // For an easiest processing of the last line. // We don't call defaultquestion() here, it will be called later. foreach ($lines as $line) { $nlinecounter++; $line = core_text::convert($line, 'windows-1252', 'utf-8'); // Processing multiples lines strings. if (isset($questiontext) and is_string($questiontext)) { if (preg_match("~^:~", $line)) { $questiontext = $this->text_field(trim($questiontext)); $question->questiontext = $questiontext['text']; $question->questiontextformat = $questiontext['format']; if (isset($questiontext['itemid'])) { $question->questiontextitemid = $questiontext['itemid']; } unset($questiontext); } else { $questiontext .= str_replace('\\:', ':', $line); continue; } } if (isset($answertext) and is_string($answertext)) { if (preg_match("~^:~", $line)) { $answertext = trim($answertext); if ($question->qtype == 'multichoice' || $question->qtype == 'match') { $question->answer[$currentchoice] = $this->text_field($answertext); $question->subanswers[$currentchoice] = $question->answer[$currentchoice]; } else { $question->answer[$currentchoice] = $answertext; $question->subanswers[$currentchoice] = $answertext; } unset($answertext); } else { $answertext .= str_replace('\\:', ':', $line); continue; } } if (isset($responsetext) and is_string($responsetext)) { if (preg_match("~^:~", $line)) { $question->subquestions[$currentchoice] = trim($responsetext); unset($responsetext); } else { $responsetext .= str_replace('\\:', ':', $line); continue; } } if (isset($feedbacktext) and is_string($feedbacktext)) { if (preg_match("~^:~", $line)) { $question->feedback[$currentchoice] = $this->text_field(trim($feedbacktext)); unset($feedbacktext); } else { $feedbacktext .= str_replace('\\:', ':', $line); continue; } } if (isset($generalfeedbacktext) and is_string($generalfeedbacktext)) { if (preg_match("~^:~", $line)) { $question->tempgeneralfeedback = trim($generalfeedbacktext); unset($generalfeedbacktext); } else { $generalfeedbacktext .= str_replace('\\:', ':', $line); continue; } } if (isset($graderinfo) and is_string($graderinfo)) { if (preg_match("~^:~", $line)) { $question->graderinfo['text'] = trim($graderinfo); $question->graderinfo['format'] = FORMAT_HTML; unset($graderinfo); } else { $graderinfo .= str_replace('\\:', ':', $line); continue; } } $line = trim($line); if (preg_match("~^:(TYPE|EOF):~i", $line)) { // New Question or End of File. if (isset($question)) { // If previous question exists, complete, check and save it. // Setup default value of missing fields. if (!isset($question->name)) { $question->name = $this->create_default_question_name($question->questiontext, get_string('questionname', 'question')); } if (!isset($question->defaultmark)) { $question->defaultmark = 1; } if (!isset($question->image)) { $question->image = ''; } // Perform sanity checks. $questionok = true; if (strlen($question->questiontext) == 0) { $warnings[] = get_string('missingquestion', 'qformat_webct', $nquestionstartline); $questionok = false; } if (count($question->answer) < 1) { // A question must have at least 1 answer. $this->error(get_string('missinganswer', 'qformat_webct', $nquestionstartline), '', $question->name); $questionok = false; } else { // Create empty feedback array. foreach ($question->answer as $key => $dataanswer) { if (!isset($question->feedback[$key])) { $question->feedback[$key]['text'] = ''; $question->feedback[$key]['format'] = FORMAT_HTML; } } // This tempgeneralfeedback allows the code to work with versions from 1.6 to 1.9. // When question->generalfeedback is undefined, the webct feedback is added to each answer feedback. if (isset($question->tempgeneralfeedback)) { if (isset($question->generalfeedback)) { $generalfeedback = $this->text_field($question->tempgeneralfeedback); $question->generalfeedback = $generalfeedback['text']; $question->generalfeedbackformat = $generalfeedback['format']; if (isset($generalfeedback['itemid'])) { $question->genralfeedbackitemid = $generalfeedback['itemid']; } } else { foreach ($question->answer as $key => $dataanswer) { if ($question->tempgeneralfeedback != '') { $question->feedback[$key]['text'] = $question->tempgeneralfeedback . '<br/>' . $question->feedback[$key]['text']; } } } unset($question->tempgeneralfeedback); } $maxfraction = -1; $totalfraction = 0; foreach ($question->fraction as $fraction) { if ($fraction > 0) { $totalfraction += $fraction; } if ($fraction > $maxfraction) { $maxfraction = $fraction; } } switch ($question->qtype) { case 'shortanswer': if ($maxfraction != 1) { $maxfraction = $maxfraction * 100; $this->error(get_string('wronggrade', 'qformat_webct', $nlinecounter) . ' ' . get_string('fractionsnomax', 'question', $maxfraction), '', $question->name); $questionok = false; } break; case 'multichoice': $question = $this->add_blank_combined_feedback($question); if ($question->single) { if ($maxfraction != 1) { $maxfraction = $maxfraction * 100; $this->error(get_string('wronggrade', 'qformat_webct', $nlinecounter) . ' ' . get_string('fractionsnomax', 'question', $maxfraction), '', $question->name); $questionok = false; } } else { $totalfraction = round($totalfraction, 2); if ($totalfraction != 1) { $totalfraction = $totalfraction * 100; $this->error(get_string('wronggrade', 'qformat_webct', $nlinecounter) . ' ' . get_string('fractionsaddwrong', 'qtype_multichoice', $totalfraction), '', $question->name); $questionok = false; } } break; case 'calculated': foreach ($question->answer as $answer) { if ($formulaerror = qtype_calculated_find_formula_errors($answer)) { $warnings[] = "'{$question->name}': " . $formulaerror; $questionok = false; } } foreach ($question->dataset as $dataset) { $dataset->itemcount = count($dataset->datasetitem); } $question->import_process = true; break; case 'match': // MDL-10680: // Switch subquestions and subanswers. $question = $this->add_blank_combined_feedback($question); foreach ($question->subquestions as $id => $subquestion) { $temp = $question->subquestions[$id]; $question->subquestions[$id] = $question->subanswers[$id]; $question->subanswers[$id] = $temp; } if (count($question->answer) < 3) { // Add a dummy missing question. $question->name = 'Dummy question added ' . $question->name; $question->answer[] = 'dummy'; $question->subanswers[] = 'dummy'; $question->subquestions[] = 'dummy'; $question->fraction[] = '0.0'; $question->feedback[] = ''; } break; default: // No problemo. } } if ($questionok) { $questions[] = $question; // Store it. unset($question); // And prepare a new one. $question = $this->defaultquestion(); } } $nquestionstartline = $nlinecounter; } // Processing Question Header. if (preg_match("~^:TYPE:MC:1(.*)~i", $line, $webctoptions)) { // Multiple Choice Question with only one good answer. $question = $this->defaultquestion(); $question->feedback = array(); $question->qtype = 'multichoice'; $question->single = 1; // Only one answer is allowed. $ignorerestofquestion = false; continue; } if (preg_match("~^:TYPE:MC:N(.*)~i", $line, $webctoptions)) { // Multiple Choice Question with several good answers. $question = $this->defaultquestion(); $question->feedback = array(); $question->qtype = 'multichoice'; $question->single = 0; // Many answers allowed. $ignorerestofquestion = false; continue; } if (preg_match("~^:TYPE:S~i", $line)) { // Short Answer Question. $question = $this->defaultquestion(); $question->feedback = array(); $question->qtype = 'shortanswer'; $question->usecase = 0; // Ignore case. $ignorerestofquestion = false; continue; } if (preg_match("~^:TYPE:C~i", $line)) { // Calculated Question. $question = $this->defaultquestion(); $question->qtype = 'calculated'; $question->answer = array(); // No problem as they go as :FORMULA: from webct. $question->units = array(); $question->dataset = array(); $question->fraction = array('1.0'); $question->feedback = array(); $currentchoice = -1; $ignorerestofquestion = false; continue; } if (preg_match("~^:TYPE:M~i", $line)) { // Match Question. $question = $this->defaultquestion(); $question->qtype = 'match'; $question->feedback = array(); $ignorerestofquestion = false; // Match question processing is not debugged. continue; } if (preg_match("~^:TYPE:P~i", $line)) { // Paragraph Question. $question = $this->defaultquestion(); $question->qtype = 'essay'; $question->responseformat = 'editor'; $question->responserequired = 1; $question->responsefieldlines = 15; $question->attachments = 0; $question->attachmentsrequired = 0; $question->graderinfo = array('text' => '', 'format' => FORMAT_HTML); $question->feedback = array(); $question->generalfeedback = ''; $question->generalfeedbackformat = FORMAT_HTML; $question->generalfeedbackfiles = array(); $question->responsetemplate = $this->text_field(''); $question->questiontextformat = FORMAT_HTML; $ignorerestofquestion = false; // To make us pass the end-of-question sanity checks. $question->answer = array('dummy'); $question->fraction = array('1.0'); continue; } if (preg_match("~^:TYPE:~i", $line)) { // Unknow question type. $warnings[] = get_string('unknowntype', 'qformat_webct', $nlinecounter); unset($question); $ignorerestofquestion = true; // Question Type not handled by Moodle. continue; } if ($ignorerestofquestion) { continue; } if (preg_match("~^:TITLE:(.*)~i", $line, $webctoptions)) { $name = trim($webctoptions[1]); $question->name = $this->clean_question_name($name); continue; } if (preg_match("~^:IMAGE:(.*)~i", $line, $webctoptions)) { $filename = trim($webctoptions[1]); if (preg_match("~^http://~i", $filename)) { $question->image = $filename; } continue; } // Need to put the parsing of calculated items here to avoid ambitiuosness: // if question isn't defined yet there is nothing to do here (avoid notices). if (!isset($question)) { continue; } if (isset($question->qtype) && 'calculated' == $question->qtype && preg_match("~^:([[:lower:]].*|::.*)-(MIN|MAX|DEC|VAL([0-9]+))::?:?({$webctnumberregex})~", $line, $webctoptions)) { $datasetname = preg_replace('/^::/', '', $webctoptions[1]); $datasetvalue = qformat_webct_convert_formula($webctoptions[4]); switch ($webctoptions[2]) { case 'MIN': $question->dataset[$datasetname]->min = $datasetvalue; break; case 'MAX': $question->dataset[$datasetname]->max = $datasetvalue; break; case 'DEC': $datasetvalue = floor($datasetvalue); // Int only! $question->dataset[$datasetname]->length = max(0, $datasetvalue); break; default: // The VAL case. $question->dataset[$datasetname]->datasetitem[$webctoptions[3]] = new stdClass(); $question->dataset[$datasetname]->datasetitem[$webctoptions[3]]->itemnumber = $webctoptions[3]; $question->dataset[$datasetname]->datasetitem[$webctoptions[3]]->value = $datasetvalue; break; } continue; } $bishtmltext = preg_match("~:H\$~i", $line); // True if next lines are coded in HTML. if (preg_match("~^:QUESTION~i", $line)) { $questiontext = ''; // Start gathering next lines. continue; } if (preg_match("~^:ANSWER([0-9]+):([^:]+):([0-9\\.\\-]+):(.*)~i", $line, $webctoptions)) { // Shortanswer. $currentchoice = $webctoptions[1]; $answertext = $webctoptions[2]; // Start gathering next lines. $question->fraction[$currentchoice] = $webctoptions[3] / 100; continue; } if (preg_match("~^:ANSWER([0-9]+):([0-9\\.\\-]+)~i", $line, $webctoptions)) { $answertext = ''; // Start gathering next lines. $currentchoice = $webctoptions[1]; $question->fraction[$currentchoice] = $webctoptions[2] / 100; continue; } if (preg_match('~^:ANSWER:~i', $line)) { // Essay. $graderinfo = ''; // Start gathering next lines. continue; } if (preg_match('~^:FORMULA:(.*)~i', $line, $webctoptions)) { // Answer for a calculated question. ++$currentchoice; $question->answer[$currentchoice] = qformat_webct_convert_formula($webctoptions[1]); // Default settings. $question->fraction[$currentchoice] = 1.0; $question->tolerance[$currentchoice] = 0.0; $question->tolerancetype[$currentchoice] = 2; // Nominal (units in webct). $question->feedback[$currentchoice]['text'] = ''; $question->feedback[$currentchoice]['format'] = FORMAT_HTML; $question->correctanswerlength[$currentchoice] = 4; $datasetnames = question_bank::get_qtype('calculated')->find_dataset_names($webctoptions[1]); foreach ($datasetnames as $datasetname) { $question->dataset[$datasetname] = new stdClass(); $question->dataset[$datasetname]->datasetitem = array(); $question->dataset[$datasetname]->name = $datasetname; $question->dataset[$datasetname]->distribution = 'uniform'; $question->dataset[$datasetname]->status = 'private'; } continue; } if (preg_match("~^:L([0-9]+)~i", $line, $webctoptions)) { $answertext = ''; // Start gathering next lines. $currentchoice = $webctoptions[1]; $question->fraction[$currentchoice] = 1; continue; } if (preg_match("~^:R([0-9]+)~i", $line, $webctoptions)) { $responsetext = ''; // Start gathering next lines. $currentchoice = $webctoptions[1]; continue; } if (preg_match("~^:REASON([0-9]+):?~i", $line, $webctoptions)) { $feedbacktext = ''; // Start gathering next lines. $currentchoice = $webctoptions[1]; continue; } if (preg_match("~^:FEEDBACK([0-9]+):?~i", $line, $webctoptions)) { $generalfeedbacktext = ''; // Start gathering next lines. $currentchoice = $webctoptions[1]; continue; } if (preg_match('~^:FEEDBACK:(.*)~i', $line, $webctoptions)) { $generalfeedbacktext = ''; // Start gathering next lines. continue; } if (preg_match('~^:LAYOUT:(.*)~i', $line, $webctoptions)) { // Ignore since layout in question_multichoice is no more used in Moodle. // $webctoptions[1] contains either vertical or horizontal. continue; } if (isset($question->qtype) && 'calculated' == $question->qtype && preg_match('~^:ANS-DEC:([1-9][0-9]*)~i', $line, $webctoptions)) { // We can but hope that this always appear before the ANSTYPE property. $question->correctanswerlength[$currentchoice] = $webctoptions[1]; continue; } if (isset($question->qtype) && 'calculated' == $question->qtype && preg_match("~^:TOL:({$webctnumberregex})~i", $line, $webctoptions)) { // We can but hope that this always appear before the TOL property. $question->tolerance[$currentchoice] = qformat_webct_convert_formula($webctoptions[1]); continue; } if (isset($question->qtype) && 'calculated' == $question->qtype && preg_match('~^:TOLTYPE:percent~i', $line)) { // Percentage case is handled as relative in Moodle. $question->tolerance[$currentchoice] /= 100; $question->tolerancetype[$currentchoice] = 1; // Relative. continue; } if (preg_match('~^:UNITS:(.+)~i', $line, $webctoptions) and $webctunits = trim($webctoptions[1])) { // This is a guess - I really do not know how different webct units are separated... $webctunits = explode(':', $webctunits); $unitrec->multiplier = 1.0; // Webct does not seem to support this. foreach ($webctunits as $webctunit) { $unitrec->unit = trim($webctunit); $question->units[] = $unitrec; } continue; } if (!empty($question->units) && preg_match('~^:UNITREQ:(.*)~i', $line, $webctoptions) && !$webctoptions[1]) { // There are units but units are not required so add the no unit alternative. // We can but hope that the UNITS property always appear before this property. $unitrec->unit = ''; $unitrec->multiplier = 1.0; $question->units[] = $unitrec; continue; } if (!empty($question->units) && preg_match('~^:UNITCASE:~i', $line)) { // This could be important but I was not able to figure out how // it works so I ignore it for now. continue; } if (isset($question->qtype) && 'calculated' == $question->qtype && preg_match('~^:ANSTYPE:dec~i', $line)) { $question->correctanswerformat[$currentchoice] = '1'; continue; } if (isset($question->qtype) && 'calculated' == $question->qtype && preg_match('~^:ANSTYPE:sig~i', $line)) { $question->correctanswerformat[$currentchoice] = '2'; continue; } } if (count($warnings) > 0) { echo '<p>' . get_string('warningsdetected', 'qformat_webct', count($warnings)) . '</p><ul>'; foreach ($warnings as $warning) { echo "<li>{$warning}</li>"; } echo '</ul>'; } return $questions; }
/** * Send an email to a specified user * * @param stdClass $user A {@link $USER} object * @param stdClass $from A {@link $USER} object * @param string $subject plain text subject line of the email * @param string $messagetext plain text version of the message * @param string $messagehtml complete html version of the message (optional) * @param string $attachment a file on the filesystem, either relative to $CFG->dataroot or a full path to a file in $CFG->tempdir * @param string $attachname the name of the file (extension indicates MIME) * @param bool $usetrueaddress determines whether $from email address should * be sent out. Will be overruled by user profile setting for maildisplay * @param string $replyto Email address to reply to * @param string $replytoname Name of reply to recipient * @param int $wordwrapwidth custom word wrap width, default 79 * @return bool Returns true if mail was sent OK and false if there was an error. */ function email_to_user($user, $from, $subject, $messagetext, $messagehtml = '', $attachment = '', $attachname = '', $usetrueaddress = true, $replyto = '', $replytoname = '', $wordwrapwidth = 79) { global $CFG, $PAGE, $SITE; if (empty($user) or empty($user->id)) { debugging('Can not send email to null user', DEBUG_DEVELOPER); return false; } if (empty($user->email)) { debugging('Can not send email to user without email: ' . $user->id, DEBUG_DEVELOPER); return false; } if (!empty($user->deleted)) { debugging('Can not send email to deleted user: '******'BEHAT_SITE_RUNNING')) { // Fake email sending in behat. return true; } if (!empty($CFG->noemailever)) { // Hidden setting for development sites, set in config.php if needed. debugging('Not sending email due to $CFG->noemailever config setting', DEBUG_NORMAL); return true; } if (email_should_be_diverted($user->email)) { $subject = "[DIVERTED {$user->email}] {$subject}"; $user = clone $user; $user->email = $CFG->divertallemailsto; } // Skip mail to suspended users. if (isset($user->auth) && $user->auth == 'nologin' or isset($user->suspended) && $user->suspended) { return true; } if (!validate_email($user->email)) { // We can not send emails to invalid addresses - it might create security issue or confuse the mailer. debugging("email_to_user: User {$user->id} (" . fullname($user) . ") email ({$user->email}) is invalid! Not sending."); return false; } if (over_bounce_threshold($user)) { debugging("email_to_user: User {$user->id} (" . fullname($user) . ") is over bounce threshold! Not sending."); return false; } // TLD .invalid is specifically reserved for invalid domain names. // For More information, see {@link http://tools.ietf.org/html/rfc2606#section-2}. if (substr($user->email, -8) == '.invalid') { debugging("email_to_user: User {$user->id} (" . fullname($user) . ") email domain ({$user->email}) is invalid! Not sending."); return true; // This is not an error. } // If the user is a remote mnet user, parse the email text for URL to the // wwwroot and modify the url to direct the user's browser to login at their // home site (identity provider - idp) before hitting the link itself. if (is_mnet_remote_user($user)) { require_once $CFG->dirroot . '/mnet/lib.php'; $jumpurl = mnet_get_idp_jump_url($user); $callback = partial('mnet_sso_apply_indirection', $jumpurl); $messagetext = preg_replace_callback("%({$CFG->wwwroot}[^[:space:]]*)%", $callback, $messagetext); $messagehtml = preg_replace_callback("%href=[\"'`]({$CFG->wwwroot}[\\w_:\\?=#&@/;.~-]*)[\"'`]%", $callback, $messagehtml); } $mail = get_mailer(); if (!empty($mail->SMTPDebug)) { echo '<pre>' . "\n"; } $temprecipients = array(); $tempreplyto = array(); // Make sure that we fall back onto some reasonable no-reply address. $noreplyaddress = empty($CFG->noreplyaddress) ? 'noreply@' . get_host_from_url($CFG->wwwroot) : $CFG->noreplyaddress; // Make up an email address for handling bounces. if (!empty($CFG->handlebounces)) { $modargs = 'B' . base64_encode(pack('V', $user->id)) . substr(md5($user->email), 0, 16); $mail->Sender = generate_email_processing_address(0, $modargs); } else { $mail->Sender = $noreplyaddress; } $alloweddomains = null; if (!empty($CFG->allowedemaildomains)) { $alloweddomains = explode(PHP_EOL, $CFG->allowedemaildomains); } // Email will be sent using no reply address. if (empty($alloweddomains)) { $usetrueaddress = false; } if (is_string($from)) { // So we can pass whatever we want if there is need. $mail->From = $noreplyaddress; $mail->FromName = $from; // Check if using the true address is true, and the email is in the list of allowed domains for sending email, // and that the senders email setting is either displayed to everyone, or display to only other users that are enrolled // in a course with the sender. } else { if ($usetrueaddress && can_send_from_real_email_address($from, $user, $alloweddomains)) { $mail->From = $from->email; $fromdetails = new stdClass(); $fromdetails->name = fullname($from); $fromdetails->url = $CFG->wwwroot; $fromstring = $fromdetails->name; if ($CFG->emailfromvia == EMAIL_VIA_ALWAYS) { $fromstring = get_string('emailvia', 'core', $fromdetails); } $mail->FromName = $fromstring; if (empty($replyto)) { $tempreplyto[] = array($from->email, fullname($from)); } } else { $mail->From = $noreplyaddress; $fromdetails = new stdClass(); $fromdetails->name = fullname($from); $fromdetails->url = $CFG->wwwroot; $fromstring = $fromdetails->name; if ($CFG->emailfromvia != EMAIL_VIA_NEVER) { $fromstring = get_string('emailvia', 'core', $fromdetails); } $mail->FromName = $fromstring; if (empty($replyto)) { $tempreplyto[] = array($noreplyaddress, get_string('noreplyname')); } } } if (!empty($replyto)) { $tempreplyto[] = array($replyto, $replytoname); } $temprecipients[] = array($user->email, fullname($user)); // Set word wrap. $mail->WordWrap = $wordwrapwidth; if (!empty($from->customheaders)) { // Add custom headers. if (is_array($from->customheaders)) { foreach ($from->customheaders as $customheader) { $mail->addCustomHeader($customheader); } } else { $mail->addCustomHeader($from->customheaders); } } // If the X-PHP-Originating-Script email header is on then also add an additional // header with details of where exactly in moodle the email was triggered from, // either a call to message_send() or to email_to_user(). if (ini_get('mail.add_x_header')) { $stack = debug_backtrace(false); $origin = $stack[0]; foreach ($stack as $depth => $call) { if ($call['function'] == 'message_send') { $origin = $call; } } $originheader = $CFG->wwwroot . ' => ' . gethostname() . ':' . str_replace($CFG->dirroot . '/', '', $origin['file']) . ':' . $origin['line']; $mail->addCustomHeader('X-Moodle-Originating-Script: ' . $originheader); } if (!empty($from->priority)) { $mail->Priority = $from->priority; } $renderer = $PAGE->get_renderer('core'); $context = array('sitefullname' => $SITE->fullname, 'siteshortname' => $SITE->shortname, 'sitewwwroot' => $CFG->wwwroot, 'subject' => $subject, 'to' => $user->email, 'toname' => fullname($user), 'from' => $mail->From, 'fromname' => $mail->FromName); if (!empty($tempreplyto[0])) { $context['replyto'] = $tempreplyto[0][0]; $context['replytoname'] = $tempreplyto[0][1]; } if ($user->id > 0) { $context['touserid'] = $user->id; $context['tousername'] = $user->username; } if (!empty($user->mailformat) && $user->mailformat == 1) { // Only process html templates if the user preferences allow html email. if ($messagehtml) { // If html has been given then pass it through the template. $context['body'] = $messagehtml; $messagehtml = $renderer->render_from_template('core/email_html', $context); } else { // If no html has been given, BUT there is an html wrapping template then // auto convert the text to html and then wrap it. $autohtml = trim(text_to_html($messagetext)); $context['body'] = $autohtml; $temphtml = $renderer->render_from_template('core/email_html', $context); if ($autohtml != $temphtml) { $messagehtml = $temphtml; } } } $context['body'] = $messagetext; $mail->Subject = $renderer->render_from_template('core/email_subject', $context); $mail->FromName = $renderer->render_from_template('core/email_fromname', $context); $messagetext = $renderer->render_from_template('core/email_text', $context); // Autogenerate a MessageID if it's missing. if (empty($mail->MessageID)) { $mail->MessageID = generate_email_messageid(); } if ($messagehtml && !empty($user->mailformat) && $user->mailformat == 1) { // Don't ever send HTML to users who don't want it. $mail->isHTML(true); $mail->Encoding = 'quoted-printable'; $mail->Body = $messagehtml; $mail->AltBody = "\n{$messagetext}\n"; } else { $mail->IsHTML(false); $mail->Body = "\n{$messagetext}\n"; } if ($attachment && $attachname) { if (preg_match("~\\.\\.~", $attachment)) { // Security check for ".." in dir path. $temprecipients[] = array($supportuser->email, fullname($supportuser, true)); $mail->addStringAttachment('Error in attachment. User attempted to attach a filename with a unsafe name.', 'error.txt', '8bit', 'text/plain'); } else { require_once $CFG->libdir . '/filelib.php'; $mimetype = mimeinfo('type', $attachname); $attachmentpath = $attachment; // Before doing the comparison, make sure that the paths are correct (Windows uses slashes in the other direction). $attachpath = str_replace('\\', '/', $attachmentpath); // Make sure both variables are normalised before comparing. $temppath = str_replace('\\', '/', realpath($CFG->tempdir)); // If the attachment is a full path to a file in the tempdir, use it as is, // otherwise assume it is a relative path from the dataroot (for backwards compatibility reasons). if (strpos($attachpath, $temppath) !== 0) { $attachmentpath = $CFG->dataroot . '/' . $attachmentpath; } $mail->addAttachment($attachmentpath, $attachname, 'base64', $mimetype); } } // Check if the email should be sent in an other charset then the default UTF-8. if (!empty($CFG->sitemailcharset) || !empty($CFG->allowusermailcharset)) { // Use the defined site mail charset or eventually the one preferred by the recipient. $charset = $CFG->sitemailcharset; if (!empty($CFG->allowusermailcharset)) { if ($useremailcharset = get_user_preferences('mailcharset', '0', $user->id)) { $charset = $useremailcharset; } } // Convert all the necessary strings if the charset is supported. $charsets = get_list_of_charsets(); unset($charsets['UTF-8']); if (in_array($charset, $charsets)) { $mail->CharSet = $charset; $mail->FromName = core_text::convert($mail->FromName, 'utf-8', strtolower($charset)); $mail->Subject = core_text::convert($mail->Subject, 'utf-8', strtolower($charset)); $mail->Body = core_text::convert($mail->Body, 'utf-8', strtolower($charset)); $mail->AltBody = core_text::convert($mail->AltBody, 'utf-8', strtolower($charset)); foreach ($temprecipients as $key => $values) { $temprecipients[$key][1] = core_text::convert($values[1], 'utf-8', strtolower($charset)); } foreach ($tempreplyto as $key => $values) { $tempreplyto[$key][1] = core_text::convert($values[1], 'utf-8', strtolower($charset)); } } } foreach ($temprecipients as $values) { $mail->addAddress($values[0], $values[1]); } foreach ($tempreplyto as $values) { $mail->addReplyTo($values[0], $values[1]); } if ($mail->send()) { set_send_count($user); if (!empty($mail->SMTPDebug)) { echo '</pre>'; } return true; } else { // Trigger event for failing to send email. $event = \core\event\email_failed::create(array('context' => context_system::instance(), 'userid' => $from->id, 'relateduserid' => $user->id, 'other' => array('subject' => $subject, 'message' => $messagetext, 'errorinfo' => $mail->ErrorInfo))); $event->trigger(); if (CLI_SCRIPT) { mtrace('Error: lib/moodlelib.php email_to_user(): ' . $mail->ErrorInfo); } if (!empty($mail->SMTPDebug)) { echo '</pre>'; } return false; } }
print_error('cantdeterminecontext', 'local_ltiprovider'); } } } // Check that we can perform enrolments if (enrol_is_enabled('manual')) { $manual = enrol_get_plugin('manual'); } else { print_error('nomanualenrol', 'local_ltiprovider'); } // Transform to utf8 all the post and get data foreach ($_POST as $key => $value) { $_POST[$key] = core_text::convert($value, $tool->encoding); } foreach ($_GET as $key => $value) { $_GET[$key] = core_text::convert($value, $tool->encoding); } // We need an username without extended chars // Later accounts add the ConsumerKey - we silently upgrade old accounts // Might want a flag for this -- Chuck $username = local_ltiprovider_create_username($context->info['oauth_consumer_key'], $context->info['user_id']); $dbuser = $DB->get_record('user', array('username' => $username)); if (!$dbuser) { $old_username = '******' . md5($context->getUserKey()); $dbuser = $DB->get_record('user', array('username' => $old_username)); if ($dbuser) { // Probably should log this $DB->set_field('user', 'username', $username, array('id' => $dbuser->id)); } $dbuser = $DB->get_record('user', array('username' => $username)); }