diff --git a/admin/uploaduser.php b/admin/uploaduser.php index 246951b318cb6..3be938c3a4d79 100755 --- a/admin/uploaduser.php +++ b/admin/uploaduser.php @@ -3,23 +3,26 @@ /// Bulk user registration script from a comma separated file /// Returns list of users with their user ids -require_once('../config.php'); +require('../config.php'); require_once($CFG->libdir.'/adminlib.php'); +require_once($CFG->libdir.'/csvlib.class.php'); +require_once($CFG->dirroot.'/user/profile/lib.php'); require_once('uploaduser_form.php'); -$uplid = optional_param('uplid', '', PARAM_FILE); +$iid = optional_param('iid', '', PARAM_INT); $previewrows = optional_param('previewrows', 10, PARAM_INT); -$separator = optional_param('separator', 'comma', PARAM_ALPHA); +$readcount = optional_param('readcount', 0, PARAM_INT); -if (!defined('UP_LINE_MAX_SIZE')) { - define('UP_LINE_MAX_SIZE', 4096); -} +define('UU_ADDNEW', 0); +define('UU_ADDINC', 1); +define('UU_ADD_UPDATE', 2); +define('UU_UPDATE', 3); @set_time_limit(3600); // 1 hour should be enough @raise_memory_limit('256M'); if (function_exists('apache_child_terminate')) { - // if we are running from Apache, give httpd a hint that - // it can recycle the process after it's done. Apache's + // if we are running from Apache, give httpd a hint that + // it can recycle the process after it's done. Apache's // memory management is truly awful but we can help it. @apache_child_terminate(); } @@ -28,126 +31,72 @@ require_capability('moodle/site:uploadusers', get_context_instance(CONTEXT_SYSTEM)); $textlib = textlib_get_instance(); +$systemcontext = get_context_instance(CONTEXT_SYSTEM); + +$struserrenamed = get_string('userrenamed', 'admin'); +$strusernotrenamedexists = get_string('usernotrenamedexists', 'error'); +$strusernotrenamedmissing = get_string('usernotrenamedmissing', 'error'); +$strusernotrenamedoff = get_string('usernotrenamedoff', 'error'); +$strusernotrenamedadmin = get_string('usernotrenamedadmin', 'error'); + +$struserupdated = get_string('useraccountupdated', 'admin'); +$strusernotupdated = get_string('usernotupdatederror', 'error'); +$strusernotupdatednotexists = get_string('usernotupdatednotexists', 'error'); +$strusernotupdatedadmin = get_string('usernotupdatedadmin', 'error'); + +$struseradded = get_string('newuser'); +$strusernotadded = get_string('usernotaddedregistered', 'error'); +$strusernotaddederror = get_string('usernotaddederror', 'error'); + +$struserdeleted = get_string('userdeleted', 'admin'); +$strusernotdeletederror = get_string('usernotdeletederror', 'error'); +$strusernotdeletedmissing = get_string('usernotdeletedmissing', 'error'); +$strusernotdeletedoff = get_string('usernotdeletedoff', 'error'); +$strusernotdeletedadmin = get_string('usernotdeletedadmin', 'error'); + +$strcannotassignrole = get_string('cannotassignrole', 'error'); +$strduplicateusername = get_string('duplicateusername', 'error'); + +$struserauthunsupported = get_string('userauthunsupported', 'error'); + + +$errorstr = get_string('error'); -$struserrenamed = get_string('userrenamed', 'admin'); -$strusernotrenamedexists = get_string('usernotrenamedexists', 'error'); -$strusernotrenamedmissing = get_string('usernotrenamedmissing', 'error'); - -$struserupdated = get_string('useraccountupdated', 'admin'); -$strusernotupdated = get_string('usernotupdatederror', 'error'); - -$struseradded = get_string('newuser'); -$strusernotadded = get_string('usernotaddedregistered', 'error'); -$strusernotaddederror = get_string('usernotaddederror', 'error'); - -$struserdeleted = get_string('userdeleted', 'admin'); -$strusernotdeletederror = get_string('usernotdeletederror', 'error'); -$strusernotdeletedmissing = get_string('usernotdeletedmissing', 'error'); - -$strcannotassignrole = get_string('cannotassignrole', 'error'); -$strduplicateusername = get_string('duplicateusername', 'error'); -$strindent = '-->'; - -$return = $CFG->wwwroot.'/'.$CFG->admin.'/uploaduser.php'; - -// make arrays of valid fields for error checking -// the value associated to each field is: 0 = optional field, 1 = field required either in default values or in data file -$fields = array( - 'firstname' => 1, - 'lastname' => 1, - 'username' => 1, - 'email' => 1, - 'city' => 1, - 'country' => 1, - 'lang' => 1, - 'auth' => 1, - 'timezone' => 1, - 'mailformat' => 1, - 'maildisplay' => 1, - 'htmleditor' => 0, - 'ajax' => 0, - 'autosubscribe' => 1, - 'mnethostid' => 0, - 'institution' => 0, - 'department' => 0, - 'idnumber' => 0, - 'icq' => 0, - 'phone1' => 0, - 'phone2' => 0, - 'address' => 0, - 'url' => 0, - 'description' => 0, - 'icq' => 0, - 'oldusername' => 0, - 'emailstop' => 1, - 'deleted' => 0, - 'password' => 0, // changed later -); - -if (empty($uplid)) { +$returnurl = $CFG->wwwroot.'/'.$CFG->admin.'/uploaduser.php'; +$bulknurl = $CFG->wwwroot.'/'.$CFG->admin.'/user/user_bulk.php'; + +// array of all valid fields for validation +$STD_FIELDS = array('firstname', 'lastname', 'username', 'email', 'city', 'country', 'lang', 'auth', 'timezone', 'mailformat', 'maildisplay', 'htmleditor', + 'ajax', 'autosubscribe', 'mnethostid', 'institution', 'department', 'idnumber', 'icq', 'phone1', 'phone2', 'address', 'url', 'description', + 'icq', 'oldusername', 'emailstop', 'deleted', 'password'); + +$PRF_FIELDS = array(); + +if ($prof_fields = $fields = get_records_select('user_info_field')) { + foreach ($prof_fields as $prof_field) { + $PRF_FIELDS[] = 'profile_field_'.$prof_field->shortname; + } + unset($prof_fields); +} + +if (empty($iid)) { $mform = new admin_uploaduser_form1(); if ($formdata = $mform->get_data()) { - if (!$filename = make_upload_directory('temp/uploaduser/'.$USER->id, true)) { - error('Can not create temporary upload directory!', $return); - } - // use current (non-conflicting) time stamp - $uplid = time(); - while (file_exists($filename.'/'.$uplid)) { - $uplid--; - } - $filename = $filename.'/'.$uplid; - - $text = $mform->get_file_content('userfile'); - // convert to utf-8 encoding - $text = $textlib->convert($text, $formdata->encoding, 'utf-8'); - // remove Unicode BOM from first line - $text = $textlib->trim_utf8_bom($text); - // Fix mac/dos newlines - $text = preg_replace('!\r\n?!', "\n", $text); - //remove empty lines at the beginning and end - $text = trim($text); - - // verify each line has the same number of separators - this detects major breakage in files - $line = strtok($text, "\n"); - if ($line === false) { - error('Empty file', $return); //TODO: localize - } - - // test headers - $csv_delimiter = get_upload_csv_delimiter($separator); - $col_count = substr_count($line, $csv_delimiter); - if ($col_count < 2) { - error('Not enough columns, please verify the separator setting!', $return); //TODO: localize - } + $iid = csv_import_reader::get_new_iid('uploaduser'); + $cir = new csv_import_reader($iid, 'uploaduser'); - $line = explode($csv_delimiter, $line); - foreach ($line as $key => $value) { - $value = trim($value); // remove whitespace - if (!array_key_exists($value, $fields) && // if not a standard field and not an enrolment field, then we have an error - !preg_match('/^course\d+$/', $value) && !preg_match('/^group\d+$/', $value) && - !preg_match('/^type\d+$/', $value) && !preg_match('/^role\d+$/', $value)) { - error(get_string('invalidfieldname', 'error', $value), $return); - } - } + $content = $mform->get_file_content('userfile'); - $line = strtok("\n"); - if ($line === false) { - error('Only one row present, can not continue!', $return); //TODO: localize - } + $readcount = $cir->load_csv_content($content, $formdata->encoding, $formdata->delimiter_name, 'validate_user_upload_columns'); + unset($content); - while ($line !== false) { - if (substr_count($line, $csv_delimiter) !== $col_count) { - error('Incorrect file format - number of columns is not constant!', $return); //TODO: localize - } - $line = strtok("\n"); + if ($readcount === false) { + error($cir->get_error(), $returnurl); + } else if ($readcount == 0) { + error(get_string('csvemptyfile', 'error'), $returnurl); } - - // store file - $fp = fopen($filename, "w"); - fwrite($fp,$text); - fclose($fp); - // continue to second form + // continue to form2 } else { admin_externalpage_print_header(); @@ -156,351 +105,566 @@ admin_externalpage_print_footer(); die; } +} else { + $cir = new csv_import_reader($iid, 'uploaduser'); } -$mform = new admin_uploaduser_form2(); -// set initial date from form1 -$mform->set_data(array('separator'=>$separator, 'uplid'=>$uplid, 'previewrows'=>$previewrows)); +if (!$columns = $cir->get_columns()) { + error('Error reading temporary file', $returnurl); +} +$mform = new admin_uploaduser_form2(null, $columns); +// get initial date from form1 +$mform->set_data(array('iid'=>$iid, 'previewrows'=>$previewrows, 'readcount'=>$readcount)); // If a file has been uploaded, then process it if ($formdata = $mform->is_cancelled()) { - user_upload_cleanup($uplid); - redirect($return); + $cir->cleanup(true); + redirect($returnurl); -} else if ($formdata = $mform->get_data()) { +} else if ($formdata = $mform->get_data(false)) { // no magic quotes here!!! // Print the header admin_externalpage_print_header(); - print_heading(get_string('uploadusers')); + print_heading(get_string('uploadusersresult', 'admin')); + + $optype = $formdata->uutype; + + $createpasswords = (!empty($formdata->uupasswordnew) and $optype != UU_UPDATE); + $updatepasswords = (!empty($formdata->uupasswordold) and $optype != UU_ADDNEW and $optype != UU_ADDINC); + $allowrenames = (!empty($formdata->uuallowrenames) and $optype != UU_ADDNEW and $optype != UU_ADDINC); + $allowdeletes = (!empty($formdata->uuallowdeletes) and $optype != UU_ADDNEW and $optype != UU_ADDINC); + $updatetype = isset($formdata->uuupdatetype) ? $formdata->uuupdatetype : 0; + $bulk = $formdata->uubulk; + + // verification moved to two places: after upload and into form2 + $usersnew = 0; + $usersupdated = 0; + $userserrors = 0; + $deletes = 0; + $deleteerrors = 0; + $renames = 0; + $renameerrors = 0; + $usersskipped = 0; + + // caches + $ccache = array(); // course cache - do not fetch all courses here, we will not probably use them all anyway! + $rolecache = array(); // roles lookup cache + + $allowedauths = uu_allowed_auths(); + $allowedauths = array_keys($allowedauths); + $availableauths = get_list_of_plugins('auth'); + + $allowedroles = uu_allowed_roles(true); + foreach ($allowedroles as $rid=>$rname) { + $rolecache[$rid] = new object(); + $rolecache[$rid]->id = $rid; + $rolecache[$rid]->name = $rname; + if (!is_numeric($rname)) { // only non-numeric shornames are supported!!! + $rolecache[$rname] = new object(); + $rolecache[$rname]->id = $rid; + $rolecache[$rname]->name = $rname; + } + } + unset($allowedroles); - $createpassword = $formdata->createpassword; - $updateaccounts = $formdata->updateaccounts; - $allowrenames = $formdata->allowrenames; - $skipduplicates = $formdata->duplicatehandling; + // clear bilk selection + if ($bulk) { + $SESSION->bulk_susers = array(); + } - $fields['password'] = !$createpassword; + // init csv import helper + $cir->init(); + $linenum = 1; //column header is first line - $filename = $CFG->dataroot.'/temp/uploaduser/'.$USER->id.'/'.$uplid; - if (!file_exists($filename)) { - user_upload_cleanup($uplid); - error('Error reading temporary file!', $return); //TODO: localize - } - if (!$fp = fopen($filename, "r")) { - user_upload_cleanup($uplid); - error('Error reading temporary file!', $return); //TODO: localize - } - - $csv_delimiter = get_upload_csv_delimiter($separator); - $csv_encode = get_upload_csv_encode($csv_delimiter); - - // find header row - $headers = array(); - $linenum = 1; - $line = explode($csv_delimiter, fgets($fp, UP_LINE_MAX_SIZE)); - - // prepare headers - foreach ($line as $key => $value) { - $headers[$key] = trim($value); - } + // init upload progress tracker + $upt = new uu_progress_tracker(); + $upt->init(); // start table - // check that required fields are present or a default value for them exists - $headersOk = true; - // disable the check if we also have deleting information (ie. deleted column) - if (!in_array('deleted', $headers)) { - foreach ($fields as $key => $required) { - if($required && !in_array($key, $headers) && (!isset($formdata->$key) || $formdata->$key==='')) { - notify(get_string('missingfield', 'error', $key)); - $headersOk = false; + while ($line = $cir->next()) { + $upt->flush(); + $linenum++; + + $upt->track('line', $linenum); + + $user = new object(); + // by default, use the local mnet id (this may be changed in the file) + $user->mnethostid = $CFG->mnet_localhost_id; + // add fields to user object + foreach ($line as $key => $value) { + if ($value !== '') { + $key = $columns[$key]; + // password is special field + if ($key == 'password') { + if ($value !== '') { + $user->password = hash_internal_user_password($value); + } + } else { + $user->$key = $value; + if (in_array($key, $upt->columns)) { + $upt->track($key, $value); + } + } } } - } - if ($headersOk) { - $usersnew = 0; - $usersupdated = 0; - $userserrors = 0; - $usersdeleted = 0; - $renames = 0; - $renameerrors = 0; - $deleteerrors = 0; - $newusernames = array(); - // We'll need courses a lot, so fetch it early and keep it in memory, indexed by their shortname - $tmp =& get_courses('all','','id,shortname,visible'); - $courses = array(); - foreach ($tmp as $c) { - $courses[$c->shortname] = $c; + + // get username, first/last name now - we need them in templates!! + if ($optype == UU_UPDATE) { + // when updating only username is required + if (!isset($user->username)) { + $upt->track('status', get_string('missingfield', 'error', 'username'), 'error'); + $upt->track('username', $errorstr, 'error'); + $userserrors++; + continue; + } + + } else { + $error = false; + // when all other ops need firstname and lastname + if (!isset($user->firstname) or $user->firstname === '') { + $upt->track('status', get_string('missingfield', 'error', 'firstname'), 'error'); + $upt->track('firstname', $errorstr, 'error'); + $error = true; + } + if (!isset($user->lastname) or $user->lastname === '') { + $upt->track('status', get_string('missingfield', 'error', 'lastname'), 'error'); + $upt->track('lastname', $errorstr, 'error'); + $error = true; + } + if ($error) { + $userserrors++; + continue; + } + // we require username too - we might use template for it though + if (!isset($user->username)) { + if (!isset($formdata->username) or $formdata->username === '') { + $upt->track('status', get_string('missingfield', 'error', 'username'), 'error'); + $upt->track('username', $errorstr, 'error'); + $userserrors++; + continue; + } else { + $user->username = process_template($formdata->username, $user); + $upt->track('username', $user->username); + } + } } - unset($tmp); - - echo '
';
- while (!feof($fp)) {
- $linenum++;
- $line = explode($csv_delimiter, fgets($fp, UP_LINE_MAX_SIZE));
- $errors = '';
- $user = new object();
- // by default, use the local mnet id (this may be changed in the file)
- $user->mnethostid = $CFG->mnet_localhost_id;
- // add fields to user object
- foreach ($line as $key => $value) {
- if($value !== '') {
- $key = $headers[$key];
- //decode encoded commas
- $value = str_replace($csv_encode,$csv_delimiter,trim($value));
- // special fields: password and username
- if ($key == 'password' && !empty($value)) {
- $user->$key = hash_internal_user_password($value);
- } else if($key == 'username') {
- $value = $textlib->strtolower(addslashes($value));
- if(empty($CFG->extendedusernamechars)) {
- $value = eregi_replace('[^(-\.[:alnum:])]', '', $value);
- }
- @$newusernames[$value]++;
- $user->$key = $value;
- } else {
- $user->$key = addslashes($value);
- }
+
+ // normalize username
+ $user->username = $textlib->strtolower($user->username);
+ if (empty($CFG->extendedusernamechars)) {
+ $user->username = eregi_replace('[^(-\.[:alnum:])]', '', $user->username);
+ }
+ if (empty($user->username)) {
+ $upt->track('status', get_string('missingfield', 'error', 'username'), 'error');
+ $upt->track('username', $errorstr, 'error');
+ $userserrors++;
+ continue;
+ }
+
+ if ($existinguser = get_record('user', 'username', addslashes($user->username), 'mnethostid', $user->mnethostid)) {
+ $upt->track('id', $existinguser->id, 'normal', false);
+ }
+
+ // find out in username incrementing required
+ if ($existinguser and $optype == UU_ADDINC) {
+ $oldusername = $user->username;
+ $user->username = increment_username($user->username, $user->mnethostid);
+ $upt->track('username', '', 'normal', false); // clear previous
+ $upt->track('username', $oldusername.'-->'.$user->username, 'info');
+ $existinguser = false;
+ }
+
+ // add default values for remaining fields
+ foreach ($STD_FIELDS as $field) {
+ if (isset($user->$field)) {
+ continue;
+ }
+ // all validation moved to form2
+ if (isset($formdata->$field)) {
+ // process templates
+ $user->$field = process_template($formdata->$field, $user);
+ }
+ }
+ foreach ($PRF_FIELDS as $field) {
+ if (isset($user->$field)) {
+ continue;
+ }
+ if (isset($formdata->$field)) {
+ // process templates
+ $user->$field = process_template($formdata->$field, $user);
+ }
+ }
+
+ // delete user
+ if (!empty($user->deleted)) {
+ if (!$allowdeletes) {
+ $usersskipped++;
+ $upt->track('status', $strusernotdeletedoff, 'warning');
+ continue;
+ }
+ if ($existinguser) {
+ if (has_capability('moodle/site:doanything', $systemcontext, $existinguser->id)) {
+ $upt->track('status', $strusernotdeletedadmin, 'error');
+ $deleteerrors++;
+ continue;
+ }
+ if (delete_user($existinguser)) {
+ $upt->track('status', $struserdeleted);
+ $deletes++;
+ } else {
+ $upt->track('status', $strusernotdeletederror, 'error');
+ $deleteerrors++;
}
+ } else {
+ $upt->track('status', $strusernotdeletedmissing, 'error');
+ $deleteerrors++;
+ }
+ continue;
+ }
+ // we do not need the deleted flag anymore
+ unset($user->deleted);
+
+ // renaming requested?
+ if (!empty($user->oldusername) ) {
+ $oldusername = $textlib->strtolower($user->oldusername);
+ if (!$allowrenames) {
+ $usersskipped++;
+ $upt->track('status', $strusernotrenamedoff, 'warning');
+ continue;
+ }
+
+ if ($existinguser) {
+ $upt->track('status', $strusernotrenamedexists, 'error');
+ $renameerrors++;
+ continue;
}
- // add default values for remaining fields
- foreach ($fields as $key => $required) {
- if(isset($user->$key)) {
+ if ($olduser = get_record('user', 'username', addslashes($oldusername), 'mnethostid', $user->mnethostid)) {
+ $upt->track('id', $olduser->id, 'normal', false);
+ if (has_capability('moodle/site:doanything', $systemcontext, $olduser->id)) {
+ $upt->track('status', $strusernotrenamedadmin, 'error');
+ $renameerrors++;
continue;
}
- if(!isset($formdata->$key) || $formdata->$key==='') { // no default value was submited
- // if the field is required, give an error only if we are adding the user or deleting a user with unkown username
- if($required && (empty($user->deleted) || $key == 'username')) {
- $errors .= get_string('missingfield', 'error', $key) . ' ';
- }
+ if (set_field('user', 'username', addslashes($user->username), 'id', $olduser->id)) {
+ $upt->track('username', '', 'normal', false); // clear previous
+ $upt->track('username', $oldusername.'-->'.$user->username, 'info');
+ $upt->track('status', $struserrenamed);
+ $renames++;
+ } else {
+ $upt->track('status', $strusernotrenamedexists, 'error');
+ $renameerrors++;
continue;
}
- // process templates
- $template = $formdata->$key;
- $templatelen = strlen($template);
- $value = '';
- for ($i = 0 ; $i < $templatelen; ++$i) {
- if($template[$i] == '%') {
- $case = 0; // 1=lowercase, 2=uppercase
- $len = 0; // number of characters to keep
- $info = null; // data to process
- for($j = $i + 1; is_null($info) && $j < $templatelen; ++$j) {
- $car = $template[$j];
- if ($car >= '0' && $car <= '9') {
- $len = $len * 10 + (int)$car;
- } else if($car == '-') {
- $case = 1;
- } else if($car == '+') {
- $case = 2;
- } else if($car == 'f') { // first name
- $info = @$user->firstname;
- } else if($car == 'l') { // last name
- $info = @$user->lastname;
- } else if($car == 'u') { // username
- $info = @$user->username;
- } else if($car == '%' && $j == $i+1) {
- $info = '%';
- } else { // invalid character
- $info = '';
- }
- }
- if($info==='' || is_null($info)) { // invalid template
+ } else {
+ $upt->track('status', $strusernotrenamedmissing, 'error');
+ $renameerrors++;
+ continue;
+ }
+ $existinguser = $olduser;
+ $existinguser->username = $user->username;
+ }
+
+ // can we process with update or insert?
+ $skip = false;
+ switch ($optype) {
+ case UU_ADDNEW:
+ if ($existinguser) {
+ $usersskipped++;
+ $upt->track('status', $strusernotadded, 'warning');
+ $skip = true;;
+ }
+ break;
+
+ case UU_ADDINC:
+ if ($existinguser) {
+ //this should not happen!
+ $upt->track('status', $strusernotaddederror, 'error');
+ $userserrors++;
+ continue;
+ }
+ break;
+
+ case UU_ADD_UPDATE:
+ break;
+
+ case UU_UPDATE:
+ if (!$existinguser) {
+ $usersskipped++;
+ $upt->track('status', $strusernotupdatednotexists, 'warning');
+ $skip = true;
+ }
+ break;
+ }
+
+ if ($skip) {
+ continue;
+ }
+
+ if ($existinguser) {
+ $user->id = $existinguser->id;
+
+ if (has_capability('moodle/site:doanything', $systemcontext, $user->id)) {
+ $upt->track('status', $strusernotupdatedadmin, 'error');
+ $userserrors++;
+ continue;
+ }
+
+ if (!$updatetype) {
+ // no updates of existing data at all
+ } else {
+ $existinguser->timemodified = time();
+ //load existing profile data
+ profile_load_data($existinguser);
+
+ $allowed = array();
+ if ($updatetype == 1) {
+ $allowed = $columns;
+ } else if ($updatetype == 2 or $updatetype == 3) {
+ $allowed = array_merge($STD_FIELDS, $PRF_FIELDS);
+ }
+ foreach ($allowed as $column) {
+ if ($column == 'username') {
+ continue;
+ }
+ if ($column == 'password') {
+ if (!$updatepasswords or $updatetype == 3) {
continue;
+ } else if (!empty($user->password)) {
+ $upt->track('password', get_string('updated'));
}
- $i = $j - 1;
- // change case
- if($case == 1) {
- $info = $textlib->strtolower($info);
- } else if($case == 2) {
- $info = $textlib->strtoupper($info);
+ }
+ if ((array_key_exists($column, $existinguser) and array_key_exists($column, $user)) or in_array($column, $PRF_FIELDS)) {
+ if ($updatetype == 3 and $existinguser->$column !== '') {
+ //missing == non-empty only
+ continue;
}
- if($len) { // truncate data
- $info = $textlib->substr($info, 0, $len);
+ if ($existinguser->$column !== $user->$column) {
+ if ($column != 'password' and in_array($column, $upt->columns)) {
+ $upt->track($column, '', 'normal', false); // clear previous
+ $upt->track($column, $existinguser->$column.'-->'.$user->$column, 'info');
+ }
+ $existinguser->$column = $user->$column;
}
- $value .= $info;
- } else {
- $value .= $template[$i];
}
}
- if($key == 'username') {
- $value = $textlib->strtolower($value);
- if(empty($CFG->extendedusernamechars)) {
- $value = eregi_replace('[^(-\.[:alnum:])]', '', $value);
- }
- @$newusernames[$value]++;
- // check for new username duplicates
- if($newusernames[$value] > 1) {
- if($skipduplicates) {
- $errors .= $strduplicateusername . ' (' . stripslashes($value) . '). ';
- continue;
- } else {
- $value .= $newusernames[$value];
- }
- }
+ // do not update record if new auth plguin does not exist!
+ if (!in_array($existinguser->auth, $availableauths)) {
+ $upt->track('auth', get_string('userautherror', 'error', $existinguser->auth), 'error');
+ $upt->track('status', $strusernotupdated, 'error');
+ $userserrors++;
+ continue;
+ } else if (!in_array($existinguser->auth, $allowedauths)) {
+ $upt->track('auth', $struserauthunsupported, 'warning');
}
- $user->$key = $value;
- }
- if($errors) {
- notify(get_string('erroronline', 'error', $linenum). ': ' . $errors);
- ++$userserrors;
- continue;
- }
- // delete user
- if(@$user->deleted) {
- $info = ': ' . stripslashes($user->username) . '. ';
- if($user =& get_record('user', 'username', $user->username, 'mnethostid', $user->mnethostid)) {
- $user->timemodified = time();
- $user->username = addslashes($user->email . $user->timemodified); // Remember it just in case
- $user->deleted = 1;
- $user->email = ''; // Clear this field to free it up
- $user->idnumber = ''; // Clear this field to free it up
- if (update_record('user', $user)) {
- // not sure if this is needed. unenrol_student($user->id); // From all courses
- delete_records('role_assignments', 'userid', $user->id); // unassign all roles
- // remove all context assigned on this user?
- echo $struserdeleted . $info . '
';
- ++$usersdeleted;
- } else {
- notify(get_string('erroronline', 'error', $linenum). ': ' . $strusernotdeletederror . $info);
- ++$deleteerrors;
- }
+ if (update_record('user', addslashes_recursive($existinguser))) {
+ $upt->track('status', $struserupdated);
+ $usersupdated++;
} else {
- notify(get_string('erroronline', 'error', $linenum). ': ' . $strusernotdeletedmissing . $info);
- ++$deleteerrors;
+ $upt->track('status', $strusernotupdated, 'error');
+ $userserrors++;
+ continue;
+ }
+ // save custom profile fields data from csv file
+ profile_save_data(addslashes_recursive($existinguser));
+ }
+
+ if ($bulk == 2 or $bulk == 3) {
+ if (!in_array($user->id, $SESSION->bulk_susers)) {
+ $SESSION->bulk_susers[] = $user->id;
}
- continue;
}
+ } else {
// save the user to the database
$user->confirmed = 1;
$user->timemodified = time();
- // before insert/update, check whether we should be updating an old record instead
- if ($allowrenames && !empty($user->oldusername) ) {
- $user->oldusername = $textlib->strtolower($user->oldusername);
- $info = ': ' . stripslashes($user->oldusername) . '-->' . stripslashes($user->username) . '. ';
- if ($olduser =& get_record('user', 'username', $user->oldusername, 'mnethostid', $user->mnethostid)) {
- if (set_field('user', 'username', $user->username, 'id', $olduser->id)) {
- echo $struserrenamed . $info;
- $renames++;
- } else {
- notify(get_string('erroronline', 'error', $linenum). ': ' . $strusernotrenamedexists . $info);
- $renameerrors++;
- continue;
- }
- } else {
- notify(get_string('erroronline', 'error', $linenum). ': ' . $strusernotrenamedmissing . $info);
- $renameerrors++;
+ if (!$createpasswords and empty($user->password)) {
+ $upt->track('password', get_string('missingfield', 'error', 'password'), 'error');
+ $upt->track('status', $strusernotaddederror, 'error');
+ $userserrors++;
+ continue;
+ }
+
+ // do not insert record if new auth plguin does not exist!
+ if (isset($user->auth)) {
+ if (!in_array($user->auth, $availableauths)) {
+ $upt->track('auth', get_string('userautherror', 'error', $user->auth), 'error');
+ $upt->track('status', $strusernotaddederror, 'error');
+ $userserrors++;
continue;
+ } else if (!in_array($user->auth, $allowedauths)) {
+ $upt->track('auth', $struserauthunsupported, 'warning');
}
}
- // save the information
- if ($olduser =& get_record('user', 'username', $user->username, 'mnethostid', $user->mnethostid)) {
- $user->id = $olduser->id;
- $info = ': ' . stripslashes($user->username) .' (ID = ' . $user->id . ')';
- if ($updateaccounts) {
- // Record is being updated
- if (update_record('user', $user)) {
- echo $struserupdated . $info . '
';
- $usersupdated++;
- } else {
- notify(get_string('erroronline', 'error', $linenum). ': ' . $strusernotupdated . $info);
- $userserrors++;
- continue;
- }
- } else {
- //Record not added - user is already registered
- //In this case, output userid from previous registration
- //This can be used to obtain a list of userids for existing users
- echo $strusernotadded . $info . '
';
- $userserrors++;
+ if ($user->id = insert_record('user', addslashes_recursive($user))) {
+ $info = ': ' . $user->username .' (ID = ' . $user->id . ')';
+ $upt->track('status', $struseradded);
+ $upt->track('id', $user->id, 'normal', false);
+ $usersnew++;
+ if ($createpasswords and empty($user->password)) {
+ // passwords will be created and sent out on cron
+ set_user_preference('create_password', 1, $user->id);
+ set_user_preference('auth_forcepasswordchange', 1, $user->id);
+ $upt->track('password', get_string('new'));
}
- } else { // new user
- if ($user->id = insert_record('user', $user)) {
- $info = ': ' . stripslashes($user->username) .' (ID = ' . $user->id . ')';
- echo $struseradded . $info . '
';
- $usersnew++;
- if (empty($user->password) && $createpassword) {
- // passwords will be created and sent out on cron
- set_user_preference('create_password', 1, $user->id);
- set_user_preference('auth_forcepasswordchange', 1, $user->id);
- }
- } else {
- // Record not added -- possibly some other error
- notify(get_string('erroronline', 'error', $linenum). ': ' . $strusernotaddederror . ': ' . stripslashes($user->username));
- $userserrors++;
- continue;
+ } else {
+ // Record not added -- possibly some other error
+ $upt->track('status', $strusernotaddederror, 'error');
+ $userserrors++;
+ continue;
+ }
+ // save custom profile fields data
+ profile_save_data($user);
+
+ if ($bulk == 1 or $bulk == 3) {
+ if (!in_array($user->id, $SESSION->bulk_susers)) {
+ $SESSION->bulk_susers[] = $user->id;
}
}
+ }
+
+ // find course enrolments, groups and roles/types
+ foreach ($columns as $column) {
+ if (!preg_match('/^course\d+$/', $column)) {
+ continue;
+ }
+ $i = substr($column, 6);
- // find course enrolments, groups and roles/types
- for($ncourses = 1; $addcourse = @$user->{'course' . $ncourses}; ++$ncourses) {
- // find course
- if(!$course = @$courses[$addcourse]) {
- notify(get_string('erroronline', 'error', $linenum). ': ' . get_string('unknowncourse', 'error', $addcourse));
+ $shortname = $user->{'course'.$i};
+ if (!array_key_exists($shortname, $ccache)) {
+ if (!$course = get_record('course', 'shortname', $shortname, '', '', '', '', 'id, shortname, defaultrole')) {
+ $upt->track('enrolments', get_string('unknowncourse', 'error', $shortname), 'error');
continue;
}
- // find role
- if ($addrole = @$user->{'role' . $ncourses}) {
- $coursecontext =& get_context_instance(CONTEXT_COURSE, $course->id);
- if (!$ok = role_assign($addrole, $user->id, 0, $coursecontext->id)) {
- echo $strindent . $strcannotassignrole . '
';
- }
+ $ccache[$shortname] = $course;
+ $ccache[$shortname]->groups = null;
+ }
+ $courseid = $ccache[$shortname]->id;
+ $coursecontext = get_context_instance(CONTEXT_COURSE, $courseid);
+
+ // find role
+ $rid = false;
+ if (!empty($user->{'role'.$i})) {
+ $addrole = $user->{'role'.$i};
+ if (array_key_exists($addrole, $rolecache)) {
+ $rid = $rolecache[$addrole]->id;
} else {
- // if no role, then find "old" enrolment type
- switch ($addtype = @$user->{'type' . $ncourses}) {
- case 2: // teacher
- $ok = add_teacher($user->id, $course->id, 1);
- break;
- case 3: // non-editing teacher
- $ok = add_teacher($user->id, $course->id, 0);
- break;
- case 1: // student
- default:
- $ok = enrol_student($user->id, $course->id);
- break;
+ $upt->track('enrolments', get_string('unknownrole', 'error', $addrole), 'error');
+ continue;
+ }
+
+ } else if (!empty($user->{'type'.$i})) {
+ // if no role, then find "old" enrolment type
+ $addtype = $user->{'type'.$i};
+ if ($addtype < 1 or $addtype > 3) {
+ $upt->track('enrolments', $strerror.': typeN = 1|2|3', 'error');
+ continue;
+ } else if ($addtype == 1 and empty($formdata->uulegacy1)) {
+ if (empty($ccache[$shortname]->defaultrole)) {
+ $rid = $CFG->defaultcourseroleid;
+ } else {
+ $rid = $ccache[$shortname]->defaultrole;
}
+ } else {
+ $rid = $formdata->{'uulegacy'.$addtype};
+ }
+
+ } else {
+ // no role specified, use the default
+ if (empty($ccache[$shortname]->defaultrole)) {
+ $rid = $CFG->defaultcourseroleid;
+ } else {
+ $rid = $ccache[$shortname]->defaultrole;
}
- if ($ok) { // OK
- echo $strindent . get_string('enrolledincourse', '', $addcourse) . '
';
+ }
+ if ($rid) {
+ $a = new object();
+ $a->course = $shortname;
+ $a->role = $rolecache[$rid]->name;
+ if (role_assign($rid, $user->id, 0, $coursecontext->id)) {
+ $upt->track('enrolments', get_string('enrolledincourserole', '', $a));
} else {
- notify(get_string('erroronline', 'error', $linenum). ': ' . get_string('enrolledincoursenot', '', $addcourse));
+ $upt->track('enrolments', get_string('enrolledincoursenotrole', '', $a), 'error');
}
+ }
- // find group to add to
- if ($addgroup = @$user->{'group' . $ncourses}) {
- if ($gid =& groups_get_group_by_name($course->id, $addgroup)) {
- $coursecontext =& get_context_instance(CONTEXT_COURSE, $course->id);
- if (count(get_user_roles($coursecontext, $user->id))) {
- if (groups_add_member($gid, $user->id)) {
- echo $strindent . get_string('addedtogroup','',$addgroup) . '
';
- } else {
- notify(get_string('erroronline', 'error', $linenum). ': ' . get_string('addedtogroupnot','',$addgroup));
+ // find group to add to
+ if (!empty($user->{'group'.$i})) {
+ // make sure user is enrolled into course before adding into groups
+ if (!has_capability('moodle/course:view', $coursecontext, $user->id, false)) {
+ $upt->track('enrolments', get_string('addedtogroupnotenrolled', '', $gname), 'error');
+ continue;
+ }
+ //build group cache
+ if (is_null($ccache[$shortname]->groups)) {
+ $ccache[$shortname]->groups = array();
+ if ($groups = get_groups($courseid)) {
+ foreach ($groups as $gid=>$group) {
+ $ccache[$shortname]->groups[$gid] = new object();
+ $ccache[$shortname]->groups[$gid]->id = $gid;
+ $ccache[$shortname]->groups[$gid]->name = $group->name;
+ if (!is_numeric($group->name)) { // only non-numeric names are supported!!!
+ $ccache[$shortname]->groups[$group->name] = new object();
+ $ccache[$shortname]->groups[$group->name]->id = $gid;
+ $ccache[$shortname]->groups[$group->name]->name = $group->name;
}
- } else {
- notify(get_string('erroronline', 'error', $linenum). ': ' . get_string('addedtogroupnotenrolled','',$addgroup));
}
- } else {
- notify(get_string('erroronline', 'error', $linenum). ': ' . get_string('groupunknown','error',$addgroup));
}
}
+ // group exists?
+ $addgroup = $user->{'group'.$i};
+ if (!array_key_exists($addgroup, $ccache[$shortname]->groups)) {
+ $upt->track('enrolments', get_string('unknowgroup', 'error', $addgroup), 'error');
+ continue;
+ }
+ $gid = $ccache[$shortname]->groups[$addgroup]->id;
+ $gname = $ccache[$shortname]->groups[$addgroup]->name;
+
+ if (groups_add_member($gid, $user->id)) {
+ $upt->track('enrolments', get_string('addedtogroup', '', $gname));
+ } else {
+ $upt->track('enrolments', get_string('addedtogroupnot', '', $gname), 'error');
+ continue;
+ }
}
}
- echo '
';
+ if ($optype != UU_UPDATE) {
+ echo get_string('userscreated', 'admin').': '.$usersnew.'
';
+ }
+ if ($optype == UU_UPDATE or $optype == UU_ADD_UPDATE) {
+ echo get_string('usersupdated', 'admin').': '.$usersupdated.'
';
+ }
+ if ($allowdeletes) {
+ echo get_string('usersdeleted', 'admin').': '.$deletes.'
';
+ echo get_string('deleteerrors', 'admin').': '.$deleteerrors.'
';
+ }
+ if ($allowrenames) {
+ echo get_string('usersrenamed', 'admin').': '.$renames.'
';
+ echo get_string('renameerrors', 'admin').': '.$renameerrors.'
';
+ }
+ if ($usersskipped) {
+ echo get_string('usersskipped', 'admin').': '.$usersskipped.'
';
+ }
+ echo get_string('errors', 'admin').': '.$userserrors.'
'.trim($h).' | '; +echo '
---|
'.s($col).' | '; } echo '|
---|---|
'.trim(str_replace($csv_encode, $csv_delimiter, $field)).' | ';; +$cir->init(); +while ($fields = $cir->next()) { + if ($ri > $previewrows) { + echo '|
... | ';; + } + break; } - echo '|
... | ';; + echo ''.s($field).' | ';; } + echo '
'.get_string('status').' | '; + echo ''.get_string('uucsvline', 'admin').' | '; + echo 'ID | '; + echo ''.get_string('username').' | '; + echo ''.get_string('firstname').' | '; + echo ''.get_string('lastname').' | '; + echo ''.get_string('email').' | '; + echo ''.get_string('password').' | '; + echo ''.get_string('authentication').' | '; + echo ''.get_string('enrolments').' | '; + echo ''.get_string('delete').' | '; + echo '
---|---|---|---|---|---|---|---|---|---|---|
';
+ if (!empty($field)) {
+ echo implode(' ', $field); + } else { + echo ' '; + } + echo ' | ';
+ }
+ echo '
Firstly, note that it is usually not necessary to import users in bulk - to keep your own maintenance work down you should first explore forms of authentication that do not require manual maintenance, such as connecting to existing external databases or letting the users create their own accounts. See the Authentication section in the admin menus.
+Firstly, note that it is usually not necessary to import users in bulk - to keep your own maintenance work down +you should first explore forms of authentication that do not require manual maintenance, such as connecting to existing external +databases or letting the users create their own accounts. See the Authentication section in the admin menus.
If you are sure you want to import multiple user accounts from a text file, then you need to format your text file as follows:
Required fieldnames: these fields must be included in the first record, and defined for each user
--
firstname, lastname
Optional fieldnames: all of these are completely optional. If a values is present for the field in the file, then that value is used; else, the default value for that field is used.
--
institution, department, city, country, lang, auth, timezone, idnumber, icq, phone1, phone2, address, url, description, mailformat, maildisplay, htmleditor, autosubscribe, emailstop, deleted
Enrolment fieldnames (optional): The course names are the "shortnames" of the courses - if present then the user will be enrolled in those courses. For groups use group name; for roles use id. Group names must be associated to the corresponding courses, i.e. group1 to course1, etc.
-+
course1, group1, type1, role1, course2, group2, type2, role2, etc.
+
firstname, lastname
when inserting orusername
when updatingOptional fieldnames: all of these are completely optional. If a values is present for the field in the file, then that value is used; else, the default value for that field is used.
++
institution, department, city, country, lang, auth, ajax, timezone, idnumber, icq, phone1, phone2, address, url, description, mailformat, maildisplay, htmleditor, autosubscribe, emailstop
Special fieldnames: used for changing of usernames and deleting of users, see bellow
++
deleted, oldusername
Enrolment fieldnames (optional): The course names are the "shortnames" of the courses - if present + then the user will be enrolled in those courses. "Type" means type of role to be used for associated course enrolment. + Value 1 is default course role, 2 is legacy Teacher role and 3 is legacy Non-editing Teacher. You can use role field instead + to specify roles directly - use either role short name or id (numeric names of roles are not supported). Users may be also + assigned to groups in course (group1 in course1, group2 in course2, etc.). Groups are again identified by its names or ids + (numeric names of groups are not supported).
+
course1, type1, role1, group1, course2, type2, role2, group2, etc.
Here is an example of a valid import file:
username, password, firstname, lastname, email, lang, idnumber, maildisplay, course1, group1, type1
jonest, verysecret, Tom, Jones, jonest@someplace.edu, en, 3663737, 1, Intro101, Section 1, 1
reznort, somesecret, Trent, Reznor, reznort@someplace.edu, en_us, 6736733, 0, Advanced202, Section 3, 3
The CSV file may contain full informations for some users and use default values for others (use extra commas to corectly associate data to headers). For example, the following file will use default values for username, city and country for user Trent Reznor:
-username, password, firstname, lastname, country, city
-jonest, verysecret, Tom, Jones, RO, Constanta
-, somesecret, Trent, Reznor, ,
-
The default values are processed as templates in which the following codes are allowed:
@@ -44,8 +44,9 @@Between the percent sign (%) and any code letter (l, f or u) the following modifiers are allowed:
Template processing is done only on default values, and not on the values retrieved from the CSV file.
-In order to create corect Moodle usernames, the username is always converted to lowercase. Moreover, if the "Allow extended characters in usernames" option in the Site policies page is off, characters different to letters, digits, dash (-) and dot (.) are removed. +
In order to create correct Moodle usernames, the username is always converted to lowercase. Moreover, if the "Allow extended characters in usernames" option in the Site policies page is off, characters different to letters, digits, dash (-) and dot (.) are removed. For example if the firstname is John Jr. and the lastname is Doe, the username %-f_%-l will produce john jr._doe when Allow extended characters in usernames is on, and johnjr.doe when off.
When the "New username duplicate handling" setting is set to Append counter, an auto-increment counter will be append to duplicate usernames produced by the template. For example, if the CSV file contains the users named John Doe, Jane Doe and Jenny Doe without explicit usernames, the default username is %-1f%-l and New username duplicate handling is set to Append counter, then the usernames produced will be jdoe, jdoe2 and jdoe3. @@ -66,14 +67,14 @@
By default Moodle assumes that you will be creating new user accounts, and skips records where the username matches an existing account. However, if you set "Update existing accounts" to Yes, the existing user account will be updated.
+By default Moodle assumes that you will be creating new user accounts, and skips records where the username matches an existing account. However, if you allow updating, the existing user account will be updated.
When updating existing accounts you can change usernames as well. Set "Allow renames" to Yes and include in your file a field called oldusername
.
Warning: any errors updating existing accounts can affect your users badly. Be careful when using the options to update.
If the deleted
field is present, users with value 1 for it will be deleted. In this case, all the fields may be omitted, except for username
(which should be present in the CSV file, or a default value for it should be available).
If the deleted
field is present, users with value 1 for it will be deleted. In this case, all the fields may be omitted, except for username
.
Deleting and uploading accounts could be done with a single CSV file. For example, the following file will add the user Tom Jones and delete the user reznort:
username, firstname, lastname, deleted
jonest, Tom, Jones, 0
diff --git a/lang/en_utf8/moodle.php b/lang/en_utf8/moodle.php
index dc9c29473cc10..dc66d531d5dd4 100644
--- a/lang/en_utf8/moodle.php
+++ b/lang/en_utf8/moodle.php
@@ -23,9 +23,9 @@
$string['added'] = 'Added $a';
$string['addedrecip'] = 'Added $a new recipient';
$string['addedrecips'] = 'Added $a new recipients';
-$string['addedtogroup'] = 'Added to group $a';
-$string['addedtogroupnot'] = 'Not added to group $a';
-$string['addedtogroupnotenrolled'] = 'Not added to group $a, because not enrolled in course';
+$string['addedtogroup'] = 'Added to group \"$a\"';
+$string['addedtogroupnot'] = 'Not added to group \"$a\"';
+$string['addedtogroupnotenrolled'] = 'Not added to group \"$a\", because not enrolled in course';
$string['addinganew'] = 'Adding a new $a';
$string['addinganewto'] = 'Adding a new $a->what to $a->to';
$string['addingdatatoexisting'] = 'Adding data to existing';
@@ -539,7 +539,9 @@
$string['enrolenddaterror'] = 'Enrolment end date cannot be earlier than start date';
$string['enrollable'] = 'Course enrollable';
$string['enrolledincourse'] = 'Enrolled in course \"$a\"';
+$string['enrolledincourserole'] = 'Enrolled in \"$a->course\" as \"$a->role\"';
$string['enrolledincoursenot'] = 'Not enrolled in course \"$a\"';
+$string['enrolledincoursenotrole'] = 'Error enrolling into \"$a->course\" as \"$a->role\"';
$string['enrollfirst'] = 'You have to enrol in one of the courses before you can use the site activities';
$string['enrolme'] = 'Enrol me in this course';
$string['enrolmentconfirmation'] = 'You are about to enrol yourself as a member of this course.
Are you sure you wish to do this?';
diff --git a/lib/csvlib.class.php b/lib/csvlib.class.php
new file mode 100644
index 0000000000000..662ceef41f113
--- /dev/null
+++ b/lib/csvlib.class.php
@@ -0,0 +1,268 @@
+_iid = $iid;
+ $this->_type = $type;
+ }
+
+ /**
+ * Parse this content
+ * @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 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;
+
+ $textlib = textlib_get_instance();
+
+ $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->dataroot.'/temp/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;
+ }
+
+ /**
+ * Returns list of columns
+ * @return array
+ */
+ function get_columns() {
+ if (isset($this->_columns)) {
+ return $this->_columns;
+ }
+
+ global $USER, $CFG;
+
+ $filename = $CFG->dataroot.'/temp/csvimport/'.$this->_type.'/'.$USER->id.'/'.$this->_iid;
+ if (!file_exists($filename)) {
+ return false;
+ }
+ $fp = fopen($filename, "r");
+ $line = fgets($fp);
+ fclose($fp);
+ if ($line === false) {
+ return false;
+ }
+ $this->_columns = unserialize($line);
+ return $this->_columns;
+ }
+
+ /**
+ * Init iterator.
+ */
+ function init() {
+ global $CFG, $USER;
+
+ if (!empty($this->_fp)) {
+ $this->close();
+ }
+ $filename = $CFG->dataroot.'/temp/csvimport/'.$this->_type.'/'.$USER->id.'/'.$this->_iid;
+ if (!file_exists($filename)) {
+ return false;
+ }
+ if (!$this->_fp = fopen($filename, "r")) {
+ return false;
+ }
+ //skip header
+ return (fgets($this->_fp) !== false);
+ }
+
+ /**
+ * Get next line
+ * @return array of values
+ */
+ function next() {
+ if (empty($this->_fp) or feof($this->_fp)) {
+ return false;
+ }
+ if ($ser = fgets($this->_fp)) {
+ return unserialize($ser);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Release iteration related resources
+ */
+ function close() {
+ if (!empty($this->_fp)) {
+ fclose($this->_fp);
+ $this->_fp = null;
+ }
+ }
+
+ /**
+ * Get last error
+ * @return string error text of null if none
+ */
+ function get_error() {
+ return $this->_error;
+ }
+
+ /**
+ * Cleanup temporary data
+ * @static if $full=true
+ * @param boolean true menasdo a full cleanup - all sessions for current user, false only the active iid
+ */
+ function cleanup($full=false) {
+ global $USER, $CFG;
+
+ if ($full) {
+ @remove_dir($CFG->dataroot.'/temp/csvimport/'.$this->_type.'/'.$USER->id);
+ } else {
+ @unlink($CFG->dataroot.'/temp/csvimport/'.$this->_type.'/'.$USER->id.'/'.$this->_iid);
+ }
+ }
+
+ /**
+ * Get list of cvs delimiters
+ * @static
+ * @return array suitable for selection box
+ */
+ function get_delimiter_list() {
+ $delimiters = array('comma'=>',', 'semicolon'=>';', 'colon'=>':', 'tab'=>'\\t');
+ if (isset($CFG->CSV_DELIMITER) and strlen($CFG->CSV_DELIMITER) === 1 and !in_array($CFG->CSV_DELIMITER, $delimiters)) {
+ $delimiters['cfg'] = $CFG->CSV_DELIMITER;
+ }
+ return $delimiters;
+ }
+
+ /**
+ * Get delimiter character
+ * @static
+ * @param string separator name
+ * @return char delimiter char
+ */
+ function get_delimiter($delimiter_name) {
+ switch ($delimiter_name) {
+ case 'colon': return ':';
+ case 'semicolon': return ';';
+ case 'tab': return "\t";
+ case 'cfg': if (isset($CFG->CSV_DELIMITER)) { return $CFG->CSV_DELIMITER; } // no break; fall back to comma
+ case 'comma': return ',';
+ }
+ }
+
+ /**
+ * Get encoded delimiter character
+ * @static
+ * @param string separator name
+ * @return char encoded delimiter char
+ */
+ function get_encoded_delimiter($delimiter_name) {
+ global $CFG;
+ if ($delimiter_name == 'cfg' and isset($CFG->CSV_ENCODE)) {
+ return $CFG->CSV_ENCODE;
+ }
+ $delimiter = csv_import_reader::get_delimiter($delimiter_name);
+ return ''.ord($delimiter);
+ }
+
+ /**
+ * Create new import id
+ * @static
+ * @param string who imports?
+ * @return int iid
+ */
+ function get_new_iid($type) {
+ global $USER;
+
+ if (!$filename = make_upload_directory('temp/csvimport/'.$type.'/'.$USER->id, false)) {
+ error('Can not create temporary upload directory - verify moodledata permissions!');
+ }
+
+ // use current (non-conflicting) time stamp
+ $iiid = time();
+ while (file_exists($filename.'/'.$iiid)) {
+ $iiid--;
+ }
+
+ return $iiid;
+ }
+}
+?>
\ No newline at end of file
diff --git a/theme/standard/styles_color.css b/theme/standard/styles_color.css
index 65bdfc7b30683..ced7194d4a656 100644
--- a/theme/standard/styles_color.css
+++ b/theme/standard/styles_color.css
@@ -373,6 +373,18 @@ table.flexible .r1 {
background-color : lime;
}
+#admin-uploaduser .uuinfo {
+ background-color: #8e8;
+}
+
+#admin-uploaduser .uuwarning {
+ background-color: #ee8;
+}
+
+#admin-uploaduser .uuerror {
+ background-color: #e99;
+}
+
/***
*** Blocks
***/
diff --git a/theme/standard/styles_fonts.css b/theme/standard/styles_fonts.css
index 14b03d202ea3f..c066026a79e54 100644
--- a/theme/standard/styles_fonts.css
+++ b/theme/standard/styles_fonts.css
@@ -260,6 +260,12 @@ body#admin-index .copyright {
font-size: 0.75em;
}
+#admin-uploaduser table#uupreview {
+ font-size: 0.8em;
+}
+#admin-uploaduser table#uuresults {
+ font-size: 0.9em;
+}
/***
*** Blocks
diff --git a/theme/standard/styles_layout.css b/theme/standard/styles_layout.css
index 2fa8caa6a908a..5f1d398fcac42 100644
--- a/theme/standard/styles_layout.css
+++ b/theme/standard/styles_layout.css
@@ -1170,6 +1170,16 @@ body#admin-modules table.generaltable td.c0
display: block;
}
+#admin-uploaduser table#uuresults {
+ margin-bottom: 2em;
+}
+
+#admin-uploaduser table#uupreview,
+#admin-uploaduser table#uuresults td.cell {
+ padding-left: 3px;
+ padding-right: 3px;
+}
+
/***
*** Blocks
***/