function csv_quote($value) { global $excel; if ($excel) { return textlib::convert('"'.str_replace('"',"'",$value).'"','UTF-8','UTF-16LE'); } else { return '"'.str_replace('"',"'",$value).'"'; } }
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') { textlib::convert($data, 'UTF-8', $this->output_encoding); } return $data; }
/** * 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'] = textlib::convert($location->city, 'iso-8859-1', 'utf-8'); $info['title'][] = $info['city']; } if (!empty($location->country_code)) { $countries = get_string_manager()->get_list_of_countries(true); if (isset($countries[$location->country_code])) { // prefer our localized country names $info['country'] = $countries[$location->country_code]; } else { $info['country'] = $location->country_name; } $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://netgeo.caida.org/perl/netgeo.cgi?target=' . $ip); if ($ipdata === false) { $info['error'] = get_string('cannotnetgeo', 'error'); return $info; } $matches = null; if (!preg_match('/LAT:\\s*(-?\\d+\\.\\d+)/s', $ipdata, $matches)) { $info['error'] = get_string('iplookupfailed', 'error', $ip); return $info; } $info['latitude'] = (double) $matches[1]; if (!preg_match('/LONG:\\s*(-?\\d+\\.\\d+)/s', $ipdata, $matches)) { $info['error'] = get_string('iplookupfailed', 'error', $ip); return $info; } $info['longitude'] = (double) $matches[1]; if (preg_match('/CITY:\\s*([^<]*)/', $ipdata, $matches)) { if (!empty($matches[1])) { $info['city'] = s($matches[1]); $info['title'][] = $info['city']; } } if (preg_match('/COUNTRY:\\s*([^<]*)/', $ipdata, $matches)) { if (!empty($matches[1])) { $countrycode = $matches[1]; $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'] = $countrycode; } $info['title'][] = $info['country']; } } $info['note'] = get_string('iplookupnetgeonote', 'admin'); return $info; } }
} else if ($type === 'file') { // Large files are likely to take their time and memory. Let PHP know // that we'll take longer, and that the process should be recycled soon // to free up memory. @set_time_limit(0); @raise_memory_limit("192M"); if (function_exists('apache_child_terminate')) { @apache_child_terminate(); } $text = $form->get_file_content('userfile'); // Trim utf-8 bom. $text = textlib::trim_utf8_bom($text); // Do the encoding conversion. $rawinput = textlib::convert($text, $data->encoding); } // Replace commas with newlines and remove carriage returns. $rawinput = str_replace(array("\r\n", "\r", ","), "\n", $rawinput); $addusers = clean_param($rawinput, PARAM_NOTAGS); // Turn into array. $addusers = explode("\n", $addusers); // Remove any leading or trailing spaces. $addusers = array_map('trim', $addusers); // Filter out empty strings/false/null using array_filter. $addusers = array_filter($addusers); // Bulk add results $errors = array();
/** * 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 = textlib::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; }
/** * 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 * @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) { global $USER, $CFG; $this->close(); $this->_error = null; $content = textlib::convert($content, $encoding, 'utf-8'); // remove Unicode BOM from first line $content = textlib::trim_utf8_bom($content); // Fix mac/dos newlines $content = preg_replace('!\\r\\n?!', "\n", $content); // is there anyting in file? $columns = strtok($content, "\n"); if ($columns === false) { $this->_error = get_string('csvemptyfile', 'error'); return false; } $csv_delimiter = csv_import_reader::get_delimiter($delimiter_name); $csv_encode = csv_import_reader::get_encoded_delimiter($delimiter_name); // process header - list of columns $columns = explode($csv_delimiter, $columns); $col_count = count($columns); if ($col_count === 0) { $this->_error = get_string('csvemptyfile', 'error'); return false; } foreach ($columns as $key => $value) { $columns[$key] = str_replace($csv_encode, $csv_delimiter, trim($value)); } if ($column_validation) { $result = $column_validation($columns); if ($result !== true) { $this->_error = $result; return false; } } $this->_columns = $columns; // cached columns // open file for writing $filename = $CFG->tempdir . '/csvimport/' . $this->_type . '/' . $USER->id . '/' . $this->_iid; $fp = fopen($filename, "w"); fwrite($fp, serialize($columns) . "\n"); // again - do we have any data for processing? $line = strtok("\n"); $data_count = 0; while ($line !== false) { $line = explode($csv_delimiter, $line); foreach ($line as $key => $value) { $line[$key] = str_replace($csv_encode, $csv_delimiter, trim($value)); } if (count($line) !== $col_count) { // this is critical!! $this->_error = get_string('csvweirdcolumns', 'error'); fclose($fp); $this->cleanup(); return false; } fwrite($fp, serialize($line) . "\n"); $data_count++; $line = strtok("\n"); } fclose($fp); return $data_count; }
/** * 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 = textlib::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; }
/** * Send an email to a specified user * * @global object * @global string * @global string IdentityProvider(IDP) URL user hits to jump to mnet peer. * @uses SITEID * @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) || empty($user->email)) { $nulluser = '******'; error_log($nulluser); if (CLI_SCRIPT) { mtrace('Error: lib/moodlelib.php email_to_user(): ' . $nulluser); } return false; } if (!empty($user->deleted)) { // do not mail deleted users $userdeleted = 'User is deleted'; error_log($userdeleted); if (CLI_SCRIPT) { mtrace('Error: lib/moodlelib.php email_to_user(): ' . $userdeleted); } return false; } if (!empty($CFG->noemailever)) { // hidden setting for development sites, set in config.php if needed $noemail = 'Not sending email due to noemailever config setting'; error_log($noemail); if (CLI_SCRIPT) { mtrace('Error: lib/moodlelib.php email_to_user(): ' . $noemail); } 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 = generate_email_supportuser(); // 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)); $mail->WordWrap = $wordwrapwidth; // set word wrap 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'; // Encoding to use $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 = textlib::convert($mail->FromName, 'utf-8', strtolower($charset)); $mail->Subject = textlib::convert($mail->Subject, 'utf-8', strtolower($charset)); $mail->Body = textlib::convert($mail->Body, 'utf-8', strtolower($charset)); $mail->AltBody = textlib::convert($mail->AltBody, 'utf-8', strtolower($charset)); foreach ($temprecipients as $key => $values) { $temprecipients[$key][1] = textlib::convert($values[1], 'utf-8', strtolower($charset)); } foreach ($tempreplyto as $key => $values) { $tempreplyto[$key][1] = textlib::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); $mail->IsSMTP(); // use SMTP directly 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; } }
$mform2 = new grade_import_mapping_form(null, array('gradeitems' => $gradeitems, 'header' => $header)); // if import form is submitted if ($formdata = $mform->get_data()) { // Large files are likely to take their time and memory. Let PHP know // that we'll take longer, and that the process should be recycled soon // to free up memory. @set_time_limit(0); raise_memory_limit(MEMORY_EXTRA); // use current (non-conflicting) time stamp $importcode = get_new_importcode(); $filename = make_temp_directory('gradeimport/cvs/' . $USER->id); $filename = $filename . '/' . $importcode; $text = $mform->get_file_content('userfile'); // trim utf-8 bom /// normalize line endings and do the encoding conversion $text = textlib::convert($text, $formdata->encoding); $text = textlib::trim_utf8_bom($text); // Fix mac/dos newlines $text = preg_replace('!\\r\\n?!', "\n", $text); $fp = fopen($filename, "w"); fwrite($fp, $text); fclose($fp); if (!($fp = fopen($filename, "r"))) { print_error('cannotopenfile'); } // --- get header (field names) --- $header = explode($csv_delimiter, fgets($fp, GRADE_CSV_LINE_LENGTH)); // print some preview $numlines = 0; // 0 preview lines displayed echo $OUTPUT->heading(get_string('importpreview', 'grades'));
/** * * 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 = textlib::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; }
/** * 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'] = textlib::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; } }
/** * Write one string somewhere in the worksheet * * @param integer $row Zero indexed row * @param integer $col Zero indexed column * @param string $str The string to write * @param mixed $format The XF format for the cell */ function write_string($row, $col, $str, $format = null) { /// Calculate the internal PEAR format $format = $this->MoodleExcelFormat2PearExcelFormat($format); /// Convert the text from its original encoding to UTF-16LE if (!$this->latin_output) { /// Only if don't want to use latin (win1252) stronger output $str = textlib::convert($str, 'utf-8', 'utf-16le'); } else { /// else, convert to latin (win1252) $str = textlib::convert($str, 'utf-8', 'windows-1252'); } /// Add the string safely to the PEAR Worksheet $this->pear_excel_worksheet->writeString($row, $col, $str, $format); }
/** * 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 = textlib::convert($result, $this->encoding, 'utf-8'); } return clean_param($result, PARAM_PATH); }
/** * 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 = textlib::convert($_SERVER['REMOTE_USER'], 'iso-8859-1', 'utf-8'); switch ($this->config->ntlmsso_type) { case 'ntlm': // Format is DOMAIN\username $username = substr(strrchr($username, '\\'), 1); 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 = textlib::strtolower($username); // Compatibility hack set_cache_flag($this->pluginconfig . '/ntlmsess', $sesskey, $username, AUTH_NTLMTIMEOUT); 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 textlib::convert($html, $enc, 'utf-8'); } } return iconv('UTF-8', 'UTF-8//IGNORE', $html); }
/** * Tests the static strtoupper * @return void */ public function test_strtoupper() { $str = "Žluťoučký koníček"; $up = 'ŽLUŤOUČKÝ KONÍČEK'; $this->assertSame(textlib::strtoupper($str), $up); $iso2 = pack("H*", "ae6c75bb6f75e86bfd206b6f6eede8656b"); $this->assertSame(textlib::strtoupper($iso2, 'iso-8859-2'), textlib::convert($up, 'utf-8', 'iso-8859-2')); $win = pack("H*", "8e6c759d6f75e86bfd206b6f6eede8656b"); $this->assertSame(textlib::strtoupper($win, 'cp1250'), textlib::convert($up, 'utf-8', 'cp1250')); $str = '言語設定'; $this->assertSame(textlib::strtoupper($str), $str); $str = '简体中文'; $this->assertSame(textlib::strtoupper($str), $str); $str = pack("H*", "1b24423840386c405f446a1b2842"); //ISO-2022-JP $this->assertSame(textlib::strtoupper($str, 'ISO-2022-JP'), $str); $str = pack("H*", "8cbe8cea90dd92e8"); //SHIFT-JIS $this->assertSame(textlib::strtoupper($str, 'SHIFT-JIS'), $str); $str = pack("H*", "bcf2cce5d6d0cec4"); //GB2312 $this->assertSame(textlib::strtoupper($str, 'GB2312'), $str); $str = pack("H*", "bcf2cce5d6d0cec4"); //GB18030 $this->assertSame(textlib::strtoupper($str, 'GB18030'), $str); }
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 textlib::convert($text, $enc); } }
/** * 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 mixed $olduser Userobject before modifications * @param mixed $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 = textlib::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(textlib::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; }
/** * 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. @set_time_limit(0); 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 = textlib::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(textlib::strtolower($fields[0])); $fields[1] = trim(textlib::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 = @textlib::convert($name, $this->encoding, 'utf-8'); $original = textlib::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 '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 = @textlib::convert($name, $encoding, 'utf-8'); $original = textlib::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 = textlib::convert($content, $encoding, 'utf-8'); // remove Unicode BOM from first line $content = textlib::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. $fp = tmpfile(); 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); 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); 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); $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); fclose($filepointer); $datacount = count($columns); return $datacount; }
public function readquestions($lines) { $webctnumberregex = '[+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)((e|E|\\*10\\*\\*)([+-]?[0-9]+|\\([+-]?[0-9]+\\)))?'; $questions = array(); $errors = 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 = textlib::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. $errors[] = get_string('missinganswer', 'qformat_webct', $nquestionstartline); $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; $errors[] = "'{$question->name}': " . get_string('wronggrade', 'qformat_webct', $nlinecounter) . ' ' . get_string('fractionsnomax', 'question', $maxfraction); $questionok = false; } break; case 'multichoice': $question = $this->add_blank_combined_feedback($question); if ($question->single) { if ($maxfraction != 1) { $maxfraction = $maxfraction * 100; $errors[] = "'{$question->name}': " . get_string('wronggrade', 'qformat_webct', $nlinecounter) . ' ' . get_string('fractionsnomax', 'question', $maxfraction); $questionok = false; } } else { $totalfraction = round($totalfraction, 2); if ($totalfraction != 1) { $totalfraction = $totalfraction * 100; $errors[] = "'{$question->name}': " . get_string('wronggrade', 'qformat_webct', $nlinecounter) . ' ' . get_string('fractionsaddwrong', 'question', $totalfraction); $questionok = false; } } break; case 'calculated': foreach ($question->answers 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; unset($question->answer); // Not used in calculated question. 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->responsefieldlines = 15; $question->attachments = 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($errors) > 0) { echo '<p>' . get_string('errorsdetected', 'qformat_webct', count($errors)) . '</p><ul>'; foreach ($errors as $error) { echo "<li>{$error}</li>"; } echo '</ul>'; unset($questions); // No questions imported. } 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; }
/** * Returns HTML entity transliteration table. * @return array with (html entity => utf-8) elements */ protected static function get_entities_table() { static $trans_tbl = null; // Generate/create $trans_tbl if (!isset($trans_tbl)) { if (version_compare(phpversion(), '5.3.4') < 0) { $trans_tbl = array(); foreach (get_html_translation_table(HTML_ENTITIES) as $val => $key) { $trans_tbl[$key] = textlib::convert($val, 'ISO-8859-1', 'utf-8'); } } else { if (version_compare(phpversion(), '5.4.0') < 0) { $trans_tbl = get_html_translation_table(HTML_ENTITIES, ENT_COMPAT, 'UTF-8'); $trans_tbl = array_flip($trans_tbl); } else { $trans_tbl = get_html_translation_table(HTML_ENTITIES, ENT_COMPAT | ENT_HTML401, 'UTF-8'); $trans_tbl = array_flip($trans_tbl); } } } return $trans_tbl; }
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 textlib::convert($text, $dbenc, 'utf-8'); } }
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 = textlib::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))); }