/** * Renders form elements inside <div>s. * * @param Pieform $form The form the element is being rendered for * @param array $element The element to be rendered * @return string The element rendered inside an appropriate container */ function pieform_renderer_div(Pieform $form, $element) { /*{{{*/ $formname = $form->get_name(); // Set the class of the enclosing <div> to match that of the element $result = '<div'; if (isset($element['name'])) { $result .= ' id="' . $formname . '_' . $element['name'] . '_container"'; } if (!empty($element['class'])) { $result .= ' class="' . $element['class'] . '"'; } $result .= '>'; if (isset($element['labelhtml'])) { $result .= $element['labelhtml']; } //$result .= $builtelement; $result .= $element['html']; if (isset($element['helphtml'])) { $result .= ' ' . $element['helphtml']; } // Description - optional description of the element, or other note that should be visible // on the form itself (without the user having to hover over contextual help if ((!$form->has_errors() || $form->get_property('showdescriptiononerror')) && !empty($element['description'])) { $result .= '<div class="description"> ' . Pieform::hsc($element['description']) . "</div>"; } if (!empty($element['error'])) { $result .= '<div class="errmsg">' . Pieform::hsc($element['error']) . '</div>'; } $result .= "</div>\n"; return $result; }
/** * Renders form elements inside a <table>. * * @param Pieform $form The form the element is being rendered for * @param array $element The element to be rendered * @return string The element rendered inside an appropriate container */ function pieform_renderer_table(Pieform $form, $element) { /*{{{*/ $formname = $form->get_name(); if ($element['type'] == 'fieldset') { // Add table tags to the build element, to preserve HTML compliance $builtelement = $element['html']; if (0 === strpos($builtelement, "\n<fieldset")) { $closelegendpos = strpos($builtelement, '</legend>'); if ($closelegendpos !== false) { $closelegendpos += 9; $builtelement = substr($builtelement, 0, $closelegendpos) . '<table><tbody>' . substr($builtelement, $closelegendpos); } else { $pos = strpos($builtelement, '>') + 1; $builtelement = substr($builtelement, 0, $pos) . '<table><tbody>' . substr($builtelement, $pos); } } else { $builtelement = substr($builtelement, 0, 11) . '<table><tbody>' . substr($builtelement, 11); } $builtelement = substr($builtelement, 0, -12) . '</tbody></table></fieldset>'; $result = "\t<tr>\n\t\t<td colspan=\"2\">"; $result .= $builtelement; $result .= "</td>\n\t</tr>"; return $result; } $result = "\t<tr"; $result .= ' id="' . $formname . '_' . $element['name'] . '_container"'; // Set the class of the enclosing <tr> to match that of the element if (!empty($element['class'])) { $result .= ' class="' . $element['class'] . '"'; } $result .= ">\n\t\t"; $result .= '<th>'; if (isset($element['labelhtml'])) { $result .= $element['labelhtml']; } $result .= "</th>\n\t\t<td>"; $result .= $element['html']; if (isset($element['helphtml'])) { $result .= ' ' . $element['helphtml']; } $result .= "</td>\n\t</tr>\n"; // Description - optional description of the element, or other note that should be visible // on the form itself (without the user having to hover over contextual help if ((!$form->has_errors() || $form->get_property('showdescriptiononerror')) && !empty($element['description'])) { if ($form->get_property('descriptionintwocells')) { $result .= "\t<tr>\n\t\t<td></td><td class=\"description\">"; } else { $result .= "\t<tr>\n\t\t<td colspan=\"2\" class=\"description\">"; } $result .= $element['description']; $result .= "</td>\n\t</tr>\n"; } if (!empty($element['error'])) { $result .= "\t<tr>\n\t\t<td colspan=\"2\" class=\"errmsg\">"; $result .= $element['error']; $result .= "</td>\n\t</tr>\n"; } return $result; }
/** * The CSV file is parsed here so validation errors can be returned to the * user. The data from a successful parsing is stored in the <var>$LEAP2AFILES</var> * array so it can be accessed by the submit function * * @param Pieform $form The form to validate * @param array $values The values submitted */ function bulkimport_validate(Pieform $form, $values) { global $LEAP2AFILES, $USER; // Don't even start attempting to parse if there are previous errors if ($form->has_errors()) { return; } require_once 'csvfile.php'; $zipfile = $values['file']; if (!is_file($zipfile)) { $form->set_error('file', get_string('importfilenotafile', 'admin')); return; } if (!is_readable($zipfile)) { $form->set_error('file', get_string('importfilenotreadable', 'admin')); return; } // Create temporary directory $importdir = get_config('dataroot') . 'import/' . $USER->get('id') . '/' . time() . '/'; if (!check_dir_exists($importdir)) { throw new SystemException("Couldn't create the temporary export directory {$importdir}"); } $command = sprintf('%s %s %s', escapeshellcmd(get_config('pathtounzip')), escapeshellarg($zipfile), '-d ' . escapeshellarg($importdir)); $output = array(); exec($command, $output, $returnvar); if ($returnvar != 0) { log_debug("unzip command failed with return value {$returnvar}"); // Let's make it obvious if the cause is obvious :) if ($returnvar == 127) { log_debug("This means that 'unzip' isn't installed, or the config var \$cfg->pathtounzip is not" . " pointing at unzip (see Mahara's file lib/config-defaults.php)"); } throw new SystemException(get_string('unzipfailed', 'admin', hsc($zipfile))); } else { log_debug("Unzipped {$zipfile} into {$importdir}"); } $csvfilename = $importdir . '/usernames.csv'; if (!is_readable($csvfilename)) { $form->set_error('file', get_string('importfilemissinglisting', 'admin')); return; } $csvusers = new CsvFile($csvfilename); $csvusers->set('headerExists', false); $csvusers->set('format', array('username', 'filename')); $csvdata = $csvusers->get_data(); if (!empty($csvdata->errors['file'])) { $form->set_error('file', get_string('invalidlistingfile', 'admin')); return; } foreach ($csvdata->data as $user) { $username = $user[0]; $filename = $user[1]; $LEAP2AFILES[$username] = "{$importdir}/users/{$filename}"; } }
/** * The CSV file is parsed here so validation errors can be returned to the * user. The data from a successful parsing is stored in the <var>$LEAP2AFILES</var> * array so it can be accessed by the submit function * * @param Pieform $form The form to validate * @param array $values The values submitted */ function bulkimport_validate(Pieform $form, $values) { global $LEAP2AFILES, $USER; // Don't even start attempting to parse if there are previous errors if ($form->has_errors()) { return; } require_once 'csvfile.php'; $zipfile = $values['file']; if (!is_file($zipfile)) { $form->set_error('file', get_string('importfilenotafile', 'admin')); return; } if (!is_readable($zipfile)) { $form->set_error('file', get_string('importfilenotreadable', 'admin')); return; } // Create temporary directory $importdir = get_config('dataroot') . 'import/' . $USER->get('id') . '/' . time() . '/'; if (!check_dir_exists($importdir)) { throw new SystemException("Couldn't create the temporary export directory {$importdir}"); } $archive = new ZipArchive(); if ($archive->open($zipfile) && $archive->extractTo($importdir)) { // successfully extracted $archive->close(); log_debug("Unzipped {$zipfile} into {$importdir}"); } else { throw new SystemException(get_string('unzipfailed', 'admin', hsc($zipfile))); } $csvfilename = $importdir . '/usernames.csv'; if (!is_readable($csvfilename)) { $form->set_error('file', get_string('importfilemissinglisting', 'admin')); return; } $csvusers = new CsvFile($csvfilename); $csvusers->set('headerExists', false); $csvusers->set('format', array('username', 'filename')); $csvdata = $csvusers->get_data(); if (!empty($csvdata->errors['file'])) { $form->set_error('file', get_string('invalidlistingfile', 'admin')); return; } foreach ($csvdata->data as $user) { $username = $user[0]; $filename = $user[1]; $LEAP2AFILES[$username] = "{$importdir}/users/{$filename}"; } }
/** * The CSV file is parsed here so validation errors can be returned to the * user. The data from a successful parsing is stored in the <var>$CVSDATA</var> * array so it can be accessed by the submit function * * @param Pieform $form The form to validate * @param array $values The values submitted */ function uploadcsv_validate(Pieform $form, $values) { global $CSVDATA, $ALLOWEDKEYS, $FORMAT, $USER, $CSVERRORS; // Don't even start attempting to parse if there are previous errors if ($form->has_errors()) { return; } if ($values['file']['size'] == 0) { $form->set_error('file', $form->i18n('rule', 'required', 'required', array())); return; } require_once 'csvfile.php'; $authinstance = (int) $values['authinstance']; $institution = get_field('auth_instance', 'institution', 'id', $authinstance); if (!$USER->can_edit_institution($institution)) { $form->set_error('authinstance', get_string('notadminforinstitution', 'admin')); return; } $usernames = array(); $emails = array(); $csvusers = new CsvFile($values['file']['tmp_name']); $csvusers->set('allowedkeys', $ALLOWEDKEYS); // Now we know all of the field names are valid, we need to make // sure that the required fields are included $mandatoryfields = array('username', 'password'); $mandatoryfields = array_merge($mandatoryfields, array_keys(ArtefactTypeProfile::get_mandatory_fields())); if ($lockedprofilefields = get_column('institution_locked_profile_field', 'profilefield', 'name', $institution)) { $mandatoryfields = array_merge($mandatoryfields, $lockedprofilefields); } $csvusers->set('mandatoryfields', $mandatoryfields); $csvdata = $csvusers->get_data(); if (!empty($csvdata->errors['file'])) { $form->set_error('file', $csvdata->errors['file']); return; } foreach ($csvdata->data as $key => $line) { // If headers exists, increment i = key + 2 for actual line number $i = $csvusers->get('headerExists') ? $key + 2 : $key + 1; // Trim non-breaking spaces -- they get left in place by File_CSV foreach ($line as &$field) { $field = preg_replace('/^(\\s|\\xc2\\xa0)*(.*?)(\\s|\\xc2\\xa0)*$/', '$2', $field); } // We have a line with the correct number of fields, but should validate these fields // Note: This validation should really be methods on each profile class, that way // it can be used in the profile screen as well. $formatkeylookup = array_flip($csvdata->format); $username = $line[$formatkeylookup['username']]; $password = $line[$formatkeylookup['password']]; $email = $line[$formatkeylookup['email']]; $authobj = AuthFactory::create($authinstance); if (method_exists($authobj, 'is_username_valid') && !$authobj->is_username_valid($username)) { $CSVERRORS[] = get_string('uploadcsverrorinvalidusername', 'admin', $i); } if (record_exists_select('usr', 'LOWER(username) = ?', strtolower($username)) || isset($usernames[strtolower($username)])) { $CSVERRORS[] = get_string('uploadcsverroruseralreadyexists', 'admin', $i, $username); } if (record_exists('usr', 'email', $email) || record_exists('artefact_internal_profile_email', 'email', $email) || isset($emails[$email])) { $CSVERRORS[] = get_string('uploadcsverroremailaddresstaken', 'admin', $i, $email); } // Note: only checks for valid form are done here, none of the checks // like whether the password is too easy. The user is going to have to // change their password on first login anyway. if (method_exists($authobj, 'is_password_valid') && !$authobj->is_password_valid($password)) { $CSVERRORS[] = get_string('uploadcsverrorinvalidpassword', 'admin', $i); } $usernames[strtolower($username)] = 1; $emails[$email] = 1; } if (!empty($CSVERRORS)) { $form->set_error('file', implode("<br />\n", $CSVERRORS)); return; } $FORMAT = $csvdata->format; $CSVDATA = $csvdata->data; }
/** * Browser for files area. * * @param Pieform $form The form to render the element for * @param array $element The element to render * @return string The HTML for the element */ function pieform_element_filebrowser(Pieform $form, $element) { require_once 'license.php'; global $USER, $_PIEFORM_FILEBROWSERS; $smarty = smarty_core(); // See if the filebrowser has indicated it's a group element if (!empty($element['group'])) { $group = $element['group']; } else { // otherwise check if the form knows it's in a group setting $group = $form->get_property('group'); } // See if the filebrowser has indicated it's an institution element if (!empty($element['institution'])) { $institution = $element['institution']; } else { // otherwise check if the form knows it's in an institution setting $institution = $form->get_property('institution'); } $formid = $form->get_name(); $prefix = $formid . '_' . $element['name']; if (!empty($element['tabs'])) { $tabdata = pieform_element_filebrowser_configure_tabs($element['tabs'], $prefix); $smarty->assign('tabs', $tabdata); if (!$group && $tabdata['owner'] == 'group') { $group = $tabdata['ownerid']; } else { if (!$institution) { if ($tabdata['owner'] == 'institution') { $institution = $tabdata['ownerid']; } else { if ($tabdata['owner'] == 'site') { $institution = 'mahara'; } } } } } $userid = $group || $institution ? null : $USER->get('id'); // refresh quotas if ($userid) { $USER->quota_refresh(); } $folder = $element['folder']; if ($group && !pieform_element_filebrowser_view_group_folder($group, $folder)) { $folder = null; } $path = pieform_element_filebrowser_get_path($folder); $smarty->assign('folder', $folder); $smarty->assign('foldername', $path[0]->title); $smarty->assign('path', array_reverse($path)); $smarty->assign('highlight', $element['highlight'][0]); $smarty->assign('edit', !empty($element['edit']) ? $element['edit'] : -1); if (isset($element['browse'])) { $smarty->assign('browse', (int) $element['browse']); } $config = array_map('intval', $element['config']); if ($group && $config['edit']) { $smarty->assign('groupinfo', pieform_element_filebrowser_get_groupinfo($group)); } if ($config['select']) { if (function_exists($element['selectlistcallback'])) { if ($form->is_submitted() && $form->has_errors() && isset($_POST[$prefix . '_selected']) && is_array($_POST[$prefix . '_selected'])) { $value = array_keys($_POST[$prefix . '_selected']); } else { if (isset($element['defaultvalue'])) { $value = $element['defaultvalue']; } else { $value = null; } } // check to see if attached artefact items in $value array are actually allowed // to be seen by this user if (!empty($value)) { foreach ($value as $k => $v) { $file = artefact_instance_from_id($v); if (!$file instanceof ArtefactTypeFile && !$file instanceof ArtefactTypeFolder || !$USER->can_view_artefact($file)) { unset($value[$k]); } } } $selected = $element['selectlistcallback']($value); } $smarty->assign('selectedlist', $selected); $selectedliststr = json_encode($selected); } if ($config['uploadagreement']) { if (get_config_plugin('artefact', 'file', 'usecustomagreement')) { $smarty->assign('agreementtext', get_field('site_content', 'content', 'name', 'uploadcopyright')); } else { $smarty->assign('agreementtext', get_string('uploadcopyrightdefaultcontent', 'install')); } } else { if (!isset($config['simpleupload'])) { $config['simpleupload'] = 1; } } $licensing = '<div class="fileuploadlicense">' . license_form_files($prefix) . '</div>'; $smarty->assign('licenseform', $licensing); if ($config['resizeonuploaduseroption'] == 1) { $smarty->assign('resizeonuploadenable', get_config_plugin('artefact', 'file', 'resizeonuploadenable')); $smarty->assign('resizeonuploadmaxwidth', get_config_plugin('artefact', 'file', 'resizeonuploadmaxwidth')); $smarty->assign('resizeonuploadmaxheight', get_config_plugin('artefact', 'file', 'resizeonuploadmaxheight')); } if ($config['upload']) { $maxuploadsize = display_size(get_max_upload_size(!$institution && !$group)); $smarty->assign('maxuploadsize', $maxuploadsize); $smarty->assign('phpmaxfilesize', get_max_upload_size(false)); if ($group) { $smarty->assign('uploaddisabled', !pieform_element_filebrowser_edit_group_folder($group, $folder)); } } if (!empty($element['browsehelp'])) { $config['plugintype'] = $form->get_property('plugintype'); $config['pluginname'] = $form->get_property('pluginname'); $config['browsehelp'] = $element['browsehelp']; } $config['showtags'] = !empty($config['tag']) ? (int) $userid : 0; $config['editmeta'] = (int) ($userid && !$config['edit'] && !empty($config['tag'])); $smarty->assign('config', $config); $filters = isset($element['filters']) ? $element['filters'] : null; $filedata = ArtefactTypeFileBase::get_my_files_data($folder, $userid, $group, $institution, $filters); $smarty->assign('filelist', $filedata); $configstr = json_encode($config); $fileliststr = json_encode($filedata); $smarty->assign('prefix', $prefix); $accepts = isset($element['accept']) ? 'accept="' . Pieform::hsc($element['accept']) . '"' : ''; $smarty->assign('accepts', $accepts); $initjs = "{$prefix} = new FileBrowser('{$prefix}', {$folder}, {$configstr}, config);\n{$prefix}.filedata = {$fileliststr};"; if ($config['select']) { $initjs .= "{$prefix}.selecteddata = {$selectedliststr};"; } if (isset($tabdata)) { $initjs .= "{$prefix}.tabdata = " . json_encode($tabdata) . ';'; } $_PIEFORM_FILEBROWSERS[$prefix]['views_js'] = $initjs; $initjs .= "addLoadEvent({$prefix}.init);"; $initjs .= "upload_max_filesize = '" . get_real_size(ini_get('upload_max_filesize')) . "';"; $smarty->assign('initjs', $initjs); $smarty->assign('querybase', $element['page'] . (strpos($element['page'], '?') === false ? '?' : '&')); $params = 'folder=' . $folder; if ($group) { $params .= '&group=' . $group; } if ($institution) { $params .= '&institution=' . $institution; } $switchwidth = ArtefactTypeFileBase::get_switch_width(); $smarty->assign('switchwidth', $switchwidth); $smarty->assign('folderparams', $params); return $smarty->fetch('artefact:file:form/filebrowser.tpl'); }
/** * The CSV file is parsed here so validation errors can be returned to the * user. The data from a successful parsing is stored in the <var>$CVSDATA</var> * array so it can be accessed by the submit function * * @param Pieform $form The form to validate * @param array $values The values submitted */ function uploadcsv_validate(Pieform $form, $values) { global $CSVDATA, $ALLOWEDKEYS, $MANDATORYFIELDS, $FORMAT, $USER, $UPDATES, $MEMBERS, $GROUPS; // Don't even start attempting to parse if there are previous errors if ($form->has_errors()) { return; } if ($values['file']['size'] == 0) { $form->set_error('file', $form->i18n('rule', 'required', 'required', array())); return; } $institution = $values['institution']; if (!$USER->can_edit_institution($institution)) { $form->set_error('institution', get_string('notadminforinstitution', 'admin')); return; } require_once 'csvfile.php'; $csvgroups = new CsvFile($values['file']['tmp_name']); $csvgroups->set('allowedkeys', $ALLOWEDKEYS); $csvgroups->set('mandatoryfields', $MANDATORYFIELDS); $csvdata = $csvgroups->get_data(); if (!empty($csvdata->errors['file'])) { $form->set_error('file', $csvdata->errors['file']); return; } $csverrors = new CSVErrors(); $formatkeylookup = array_flip($csvdata->format); $shortnames = array(); $hadadmin = array(); $num_lines = count($csvdata->data); foreach ($csvdata->data as $key => $line) { // If headers exists, increment i = key + 2 for actual line number $i = $csvgroups->get('headerExists') ? $key + 2 : $key + 1; // In adding 5000 groups, this part was approx 8% of the wall time. if (!($key % 25)) { set_progress_info('uploadgroupmemberscsv', $key, $num_lines * 10, get_string('validating', 'admin')); } // Trim non-breaking spaces -- they get left in place by File_CSV foreach ($line as &$field) { $field = preg_replace('/^(\\s|\\xc2\\xa0)*(.*?)(\\s|\\xc2\\xa0)*$/', '$2', $field); } $shortname = $line[$formatkeylookup['shortname']]; $username = $line[$formatkeylookup['username']]; $role = $line[$formatkeylookup['role']]; $gid = get_field('group', 'id', 'shortname', $shortname, 'institution', $institution); if (!$gid) { $csverrors->add($i, get_string('uploadgroupmemberscsverrornosuchshortname', 'admin', $i, $shortname, $institution)); continue; } $uid = get_field_sql('SELECT id FROM {usr} WHERE LOWER(username) = ?', array(strtolower($username))); if (!$uid) { $csverrors->add($i, get_string('uploadgroupmemberscsverrornosuchusername', 'admin', $i, $username)); continue; } if ($institution != 'mahara' && !record_exists('usr_institution', 'usr', $uid, 'institution', $institution)) { $csverrors->add($i, get_string('uploadgroupmemberscsverrorusernotininstitution', 'admin', $i, $username, $institution)); continue; } if (!in_array($role, array_keys(group_get_role_info($gid)))) { $csverrors->add($i, get_string('uploadgroupmemberscsverrorinvalidrole', 'admin', $i, $role)); continue; } if (!isset($MEMBERS[$gid])) { $MEMBERS[$gid] = array(); } if (isset($MEMBERS[$gid][$uid])) { $csverrors->add($i, get_string('uploadgroupmemberscsverrorduplicateusername', 'admin', $i, $shortname, $username)); continue; } $MEMBERS[$gid][$uid] = $role; $GROUPS[$gid] = $shortname; if ($role == 'admin') { $hasadmin[$shortname] = 1; } } foreach ($GROUPS as $shortname) { if (!isset($hasadmin[$shortname])) { $csverrors->add($i, get_string('uploadgroupmemberscsverrornoadminlisted', 'admin', $i, $shortname)); } } if ($errors = $csverrors->process()) { $form->set_error('file', clean_html($errors)); return; } $FORMAT = $csvdata->format; $CSVDATA = $csvdata->data; }
/** * Renders form elements inside <div>s. * * @param Pieform $form The form the element is being rendered for * @param array $element The element to be rendered * @return string The element rendered inside an appropriate container */ function pieform_renderer_div(Pieform $form, $element) { /*{{{*/ $formname = $form->get_name(); // Set the class of the enclosing <div> to match that of the element $prefix = ''; $suffix = ''; $inner = ''; // allow forms to be rendered without a wrapping div if (!isset($element['renderelementsonly'])) { $prefix = '<div'; if (isset($element['name'])) { $prefix .= ' id="' . $formname . '_' . Pieform::hsc($element['name']) . '_container"'; } // all elements should be form groups by default except button if (!isset($element['isformgroup'])) { $element['isformgroup'] = true; } if (isset($element['type'])) { $element['isformgroup'] = $element['type'] === 'button' ? false : $element['isformgroup']; } // add form-group classes to all real form fields $formgroupclass = $element['isformgroup'] ? 'form-group' : ''; if (isset($element['class'])) { // remove form-control class and btn class (these should be on the element only) $element['class'] = str_replace("btn-", " ", $element['class']); $element['class'] = str_replace("form-control ", "", $element['class']); $element['class'] = $element['class'] . ' ' . $formgroupclass; } else { $element['class'] = $formgroupclass; } if (isset($element['collapsible'])) { $element['class'] = $element['class'] . ' collapsible-group'; } // add bootstrap has-error class to any error fields if (strpos($element['class'], 'error') !== false) { $element['class'] = $element['class'] . ' has-error'; } $prefix .= ' class="' . Pieform::hsc($element['class']) . '"'; $prefix .= '>'; } if (isset($element['labelhtml'])) { $inner .= $element['labelhtml']; } if (isset($element['prehtml'])) { $inner .= '<span class="prehtml">' . $element['prehtml'] . '</span>'; } if (isset($element['html'])) { $inner .= $element['html']; } if (isset($element['posthtml'])) { $inner .= '<span class="posthtml">' . $element['posthtml'] . '</span>'; } if (isset($element['helphtml'])) { $inner .= ' ' . $element['helphtml']; } // Description - optional description of the element, or other note that should be visible // on the form itself (without the user having to hover over contextual help if ((!$form->has_errors() || $form->get_property('showdescriptiononerror')) && !empty($element['descriptionhtml'])) { $inner .= '<div class="description"> ' . $element['descriptionhtml'] . "</div>"; } if (!empty($element['error'])) { $inner .= '<div class="errmsg">' . $element['errorhtml'] . '</div>'; } if (!isset($element['renderelementsonly'])) { $suffix .= "</div>\n"; } $result = $prefix . $inner . $suffix; return $result; }
/** * The CSV file is parsed here so validation errors can be returned to the * user. The data from a successful parsing is stored in the <var>$CVSDATA</var> * array so it can be accessed by the submit function * * @param Pieform $form The form to validate * @param array $values The values submitted */ function uploadcsv_validate(Pieform $form, $values) { global $CSVDATA, $ALLOWEDKEYS, $FORMAT, $USER, $INSTITUTIONNAME, $UPDATES; // Don't even start attempting to parse if there are previous errors if ($form->has_errors()) { return; } $steps_done = 0; $steps_total = $values['updateusers'] ? 5 : 4; if ($values['file']['size'] == 0) { $form->set_error('file', $form->i18n('rule', 'required', 'required', array())); return; } if ($USER->get('admin') || get_config_plugin('artefact', 'file', 'institutionaloverride')) { $maxquotaenabled = get_config_plugin('artefact', 'file', 'maxquotaenabled'); $maxquota = get_config_plugin('artefact', 'file', 'maxquota'); if ($maxquotaenabled && $values['quota'] > $maxquota) { $form->set_error('quota', get_string('maxquotaexceededform', 'artefact.file', display_size($maxquota))); } } require_once 'csvfile.php'; $authinstance = (int) $values['authinstance']; $institution = get_field('auth_instance', 'institution', 'id', $authinstance); if (!$USER->can_edit_institution($institution)) { $form->set_error('authinstance', get_string('notadminforinstitution', 'admin')); return; } $authobj = AuthFactory::create($authinstance); $csvusers = new CsvFile($values['file']['tmp_name']); $csvusers->set('allowedkeys', $ALLOWEDKEYS); // Now we know all of the field names are valid, we need to make // sure that the required fields are included $mandatoryfields = array('username', 'email', 'firstname', 'lastname'); if (!$values['updateusers']) { $mandatoryfields[] = 'password'; } $csvusers->set('mandatoryfields', $mandatoryfields); $csvdata = $csvusers->get_data(); if (!empty($csvdata->errors['file'])) { $form->set_error('file', $csvdata->errors['file']); return; } $csverrors = new CSVErrors(); $formatkeylookup = array_flip($csvdata->format); // First pass validates usernames & passwords in the file, and builds // up a list indexed by username. $emails = array(); if (isset($formatkeylookup['remoteuser'])) { $remoteusers = array(); } $num_lines = count($csvdata->data); $maxcsvlines = get_config('maxusercsvlines'); if ($maxcsvlines && $maxcsvlines < $num_lines) { $form->set_error('file', get_string('uploadcsverrortoomanyusers', 'admin', get_string('nusers', 'mahara', $maxcsvlines))); return; } $existing_usernames = get_records_menu('usr', '', NULL, '', 'LOWER(username) AS username, 1 AS key2'); $existing_usr_email_addresses = get_records_menu('usr', '', NULL, '', 'email, 1 AS key2'); $existing_internal_email_addresses = get_records_menu('artefact_internal_profile_email', 'verified', 1, '', 'email, 1 AS key2'); foreach ($csvdata->data as $key => $line) { // If headers exists, increment i = key + 2 for actual line number $i = $csvusers->get('headerExists') ? $key + 2 : $key + 1; if (!($key % 25)) { set_progress_info('uploaduserscsv', $key, $num_lines * $steps_total, get_string('validating', 'admin')); } // Trim non-breaking spaces -- they get left in place by File_CSV foreach ($line as &$field) { $field = preg_replace('/^(\\s|\\xc2\\xa0)*(.*?)(\\s|\\xc2\\xa0)*$/', '$2', $field); } if (count($line) != count($csvdata->format)) { $csverrors->add($i, get_string('uploadcsverrorwrongnumberoffields', 'admin', $i)); continue; } // We have a line with the correct number of fields, but should validate these fields // Note: This validation should really be methods on each profile class, that way // it can be used in the profile screen as well. $username = $line[$formatkeylookup['username']]; $password = isset($formatkeylookup['password']) ? $line[$formatkeylookup['password']] : null; $email = $line[$formatkeylookup['email']]; if (isset($remoteusers)) { $remoteuser = strlen($line[$formatkeylookup['remoteuser']]) ? $line[$formatkeylookup['remoteuser']] : null; } if (method_exists($authobj, 'is_username_valid_admin')) { if (!$authobj->is_username_valid_admin($username)) { $csverrors->add($i, get_string('uploadcsverrorinvalidusername', 'admin', $i)); } } else { if (method_exists($authobj, 'is_username_valid')) { if (!$authobj->is_username_valid($username)) { $csverrors->add($i, get_string('uploadcsverrorinvalidusername', 'admin', $i)); } } } if (!$values['updateusers']) { // Note: only checks for valid form are done here, none of the checks // like whether the password is too easy. The user is going to have to // change their password on first login anyway. if (method_exists($authobj, 'is_password_valid') && !$authobj->is_password_valid($password)) { $csverrors->add($i, get_string('uploadcsverrorinvalidpassword', 'admin', $i)); } } if (isset($emails[$email])) { // Duplicate email within this file. $csverrors->add($i, get_string('uploadcsverroremailaddresstaken', 'admin', $i, $email)); } else { if (!PHPMailer::ValidateAddress($email)) { $csverrors->add($i, get_string('uploadcsverrorinvalidemail', 'admin', $i, $email)); } else { if (!$values['updateusers']) { // The email address must be new if (array_key_exists($email, $existing_usr_email_addresses) || array_key_exists($email, $existing_internal_email_addresses)) { $csverrors->add($i, get_string('uploadcsverroremailaddresstaken', 'admin', $i, $email)); } } } } $emails[$email] = 1; if (isset($remoteusers) && $remoteuser) { if (isset($remoteusers[$remoteuser])) { $csverrors->add($i, get_string('uploadcsverrorduplicateremoteuser', 'admin', $i, $remoteuser)); } else { if (!$values['updateusers']) { if ($remoteuserowner = get_record_sql(' SELECT u.username FROM {auth_remote_user} aru JOIN {usr} u ON aru.localusr = u.id WHERE aru.remoteusername = ? AND aru.authinstance = ?', array($remoteuser, $authinstance))) { $csverrors->add($i, get_string('uploadcsverrorremoteusertaken', 'admin', $i, $remoteuser, $remoteuserowner->username)); } } } $remoteusers[$remoteuser] = true; } // If we didn't even get a username, we can't check for duplicates, so move on. if (strlen($username) < 1) { continue; } if (isset($usernames[strtolower($username)])) { // Duplicate username within this file. $csverrors->add($i, get_string('uploadcsverroruseralreadyexists', 'admin', $i, $username)); } else { if (!$values['updateusers'] && array_key_exists(strtolower($username), $existing_usernames)) { $csverrors->add($i, get_string('uploadcsverroruseralreadyexists', 'admin', $i, $username)); } $usernames[strtolower($username)] = array('username' => $username, 'password' => $password, 'email' => $email, 'lineno' => $i, 'raw' => $line); if (!empty($remoteuser) && !empty($remoteusers[$remoteuser])) { $usernames[strtolower($username)]['remoteuser'] = $remoteuser; } } } // If the admin is trying to overwrite existing users, identified by username, // this second pass performs some additional checks if ($values['updateusers']) { $key = 0; foreach ($usernames as $lowerusername => $data) { if (!($key % 25)) { set_progress_info('uploaduserscsv', $num_lines + $key, $num_lines * $steps_total, get_string('checkingupdates', 'admin')); } $key++; $line = $data['lineno']; $username = $data['username']; $password = $data['password']; $email = $data['email']; // If the user already exists, they must already be in this institution. $userinstitutions = get_records_sql_assoc("\n SELECT COALESCE(ui.institution, 'mahara') AS institution, u.id\n FROM {usr} u LEFT JOIN {usr_institution} ui ON u.id = ui.usr\n WHERE LOWER(u.username) = ?", array($lowerusername)); if ($userinstitutions) { if (!isset($userinstitutions[$institution])) { if ($institution == 'mahara') { $institutiondisplay = array(); foreach ($userinstitutions as $i) { $institutiondisplay[] = $INSTITUTIONNAME[$i->institution]; } $institutiondisplay = join(', ', $institutiondisplay); $message = get_string('uploadcsverroruserinaninstitution', 'admin', $line, $username, $institutiondisplay); } else { $message = get_string('uploadcsverrorusernotininstitution', 'admin', $line, $username, $INSTITUTIONNAME[$institution]); } $csverrors->add($line, $message); } else { // Remember that this user is being updated $UPDATES[$username] = 1; } } else { // New user, check the password if (method_exists($authobj, 'is_password_valid') && !$authobj->is_password_valid($password)) { $csverrors->add($line, get_string('uploadcsverrorinvalidpassword', 'admin', $line)); } } // Check if the email already exists and if it's owned by this user. This query can return more // than one row when there are duplicate emails already on the site. If that happens, things are // already a bit out of hand, and we'll just allow an update if this user is one of the users who // owns the email. $emailowned = get_records_sql_assoc(' SELECT LOWER(u.username) AS lowerusername, ae.principal FROM {usr} u LEFT JOIN {artefact_internal_profile_email} ae ON u.id = ae.owner AND ae.verified = 1 AND ae.email = ? WHERE ae.owner IS NOT NULL OR u.email = ?', array($email, $email)); // If the email is owned by someone else, it could still be okay provided // that other user's email is also being changed in this csv file. if ($emailowned && !isset($emailowned[$lowerusername])) { foreach ($emailowned as $e) { // Only primary emails can be set in uploadcsv, so it's an error when someone else // owns the email as a secondary. if (!$e->principal) { $csverrors->add($line, get_string('uploadcsverroremailaddresstaken', 'admin', $line, $email)); break; } // It's also an error if the email owner is not being updated in this file if (!isset($usernames[$e->lowerusername])) { $csverrors->add($line, get_string('uploadcsverroremailaddresstaken', 'admin', $line, $email)); break; } // If the other user is being updated in this file, but isn't changing their // email address, it's ok, we've already notified duplicate emails within the file. } } if (isset($remoteusers) && !empty($data['remoteuser'])) { $remoteuser = $data['remoteuser']; $remoteuserowner = get_field_sql(' SELECT LOWER(u.username) FROM {usr} u JOIN {auth_remote_user} aru ON u.id = aru.localusr WHERE aru.remoteusername = ? AND aru.authinstance = ?', array($remoteuser, $authinstance)); if ($remoteuserowner && $remoteuserowner != $lowerusername && !isset($usernames[$remoteuserowner])) { // The remote username is owned by some other user who is not being updated in this file $csverrors->add($line, get_string('uploadcsverrorremoteusertaken', 'admin', $line, $remoteuser, $remoteuserowner)); } } } } if ($errors = $csverrors->process()) { $form->set_error('file', clean_html($errors), false); return; } $FORMAT = $csvdata->format; $CSVDATA = $csvdata->data; }
/** * Browser for files area. * * @param Pieform $form The form to render the element for * @param array $element The element to render * @return string The HTML for the element */ function pieform_element_filebrowser(Pieform $form, $element) { global $USER, $_PIEFORM_FILEBROWSERS; $smarty = smarty_core(); $group = $form->get_property('group'); $institution = $form->get_property('institution'); if (!empty($element['tabs'])) { $tabdata = pieform_element_filebrowser_configure_tabs($element['tabs']); $smarty->assign('tabs', $tabdata); if (!$group && $tabdata['owner'] == 'group') { $group = $tabdata['ownerid']; } else { if (!$institution) { if ($tabdata['owner'] == 'institution') { $institution = $tabdata['ownerid']; } else { if ($tabdata['owner'] == 'site') { $institution = 'mahara'; } } } } } $userid = $group || $institution ? null : $USER->get('id'); // refresh quotas if ($userid) { $USER->quota_refresh(); } $folder = $element['folder']; $path = pieform_element_filebrowser_get_path($folder); $smarty->assign('folder', $folder); $smarty->assign('foldername', $path[0]->title); $smarty->assign('path', array_reverse($path)); $smarty->assign('highlight', $element['highlight'][0]); $smarty->assign('edit', !empty($element['edit']) ? $element['edit'] : -1); if (isset($element['browse'])) { $smarty->assign('browse', (int) $element['browse']); } $config = array_map('intval', $element['config']); if ($group && $config['edit']) { $smarty->assign('groupinfo', pieform_element_filebrowser_get_groupinfo($group)); } $formid = $form->get_name(); $prefix = $formid . '_' . $element['name']; if ($config['select']) { if (function_exists($element['selectlistcallback'])) { if ($form->is_submitted() && $form->has_errors() && isset($_POST[$prefix . '_selected']) && is_array($_POST[$prefix . '_selected'])) { $value = array_keys($_POST[$prefix . '_selected']); } else { if (isset($element['defaultvalue'])) { $value = $element['defaultvalue']; } else { $value = null; } } $selected = $element['selectlistcallback']($value); } $smarty->assign('selectedlist', $selected); $selectedliststr = json_encode($selected); } if ($config['uploadagreement']) { if (get_config_plugin('artefact', 'file', 'usecustomagreement')) { $smarty->assign('agreementtext', get_field('site_content', 'content', 'name', 'uploadcopyright')); } else { $smarty->assign('agreementtext', get_string('uploadcopyrightdefaultcontent', 'install')); } } if ($config['upload']) { $maxuploadsize = min(get_real_size(ini_get('post_max_size')), get_real_size(ini_get('upload_max_filesize'))); if (!$institution && !$group) { $userquotaremaining = $USER->get('quota') - $USER->get('quotaused'); $maxuploadsize = min($maxuploadsize, $userquotaremaining); } $maxuploadsize = display_size($maxuploadsize); $smarty->assign('maxuploadsize', $maxuploadsize); } if (!empty($element['browsehelp'])) { $config['plugintype'] = $form->get_property('plugintype'); $config['pluginname'] = $form->get_property('pluginname'); $config['browsehelp'] = $element['browsehelp']; } $config['showtags'] = !empty($config['tag']) ? (int) $userid : 0; $config['editmeta'] = (int) ($userid && !$config['edit'] && !empty($config['tag'])); $smarty->assign('config', $config); $filters = isset($element['filters']) ? $element['filters'] : null; $filedata = ArtefactTypeFileBase::get_my_files_data($folder, $userid, $group, $institution, $filters); $smarty->assign('filelist', $filedata); $configstr = json_encode($config); $fileliststr = json_encode($filedata); $smarty->assign('prefix', $prefix); $initjs = "{$prefix} = new FileBrowser('{$prefix}', {$folder}, {$configstr}, config);\n{$prefix}.filedata = {$fileliststr};"; if ($config['select']) { $initjs .= "{$prefix}.selecteddata = {$selectedliststr};"; } $_PIEFORM_FILEBROWSERS[$prefix]['views_js'] = $initjs; $initjs .= "addLoadEvent({$prefix}.init);"; $smarty->assign('initjs', $initjs); $smarty->assign('querybase', $element['page'] . (strpos($element['page'], '?') === false ? '?' : '&')); return $smarty->fetch('artefact:file:form/filebrowser.tpl'); }
/** * The CSV file is parsed here so validation errors can be returned to the * user. The data from a successful parsing is stored in the <var>$CVSDATA</var> * array so it can be accessed by the submit function * * @param Pieform $form The form to validate * @param array $values The values submitted */ function uploadcsv_validate(Pieform $form, $values) { global $CSVDATA, $ALLOWEDKEYS, $MANDATORYFIELDS, $GROUPTYPES, $FORMAT, $USER, $UPDATES, $EDITROLES; // Don't even start attempting to parse if there are previous errors if ($form->has_errors()) { return; } if ($values['file']['size'] == 0) { $form->set_error('file', $form->i18n('rule', 'required', 'required', array())); return; } $institution = $values['institution']; if (!$USER->can_edit_institution($institution)) { $form->set_error('institution', get_string('notadminforinstitution', 'admin')); return; } require_once 'csvfile.php'; $csvgroups = new CsvFile($values['file']['tmp_name']); $csvgroups->set('allowedkeys', $ALLOWEDKEYS); $csvgroups->set('mandatoryfields', $MANDATORYFIELDS); $csvdata = $csvgroups->get_data(); if (!empty($csvdata->errors['file'])) { $form->set_error('file', $csvdata->errors['file']); return; } $csverrors = new CSVErrors(); $formatkeylookup = array_flip($csvdata->format); $shortnames = array(); $displaynames = array(); foreach ($csvdata->data as $key => $line) { // If headers exists, increment i = key + 2 for actual line number $i = $csvgroups->get('headerExists') ? $key + 2 : $key + 1; // Trim non-breaking spaces -- they get left in place by File_CSV foreach ($line as &$field) { $field = preg_replace('/^(\\s|\\xc2\\xa0)*(.*?)(\\s|\\xc2\\xa0)*$/', '$2', $field); } if (count($line) != count($csvdata->format)) { $csverrors->add($i, get_string('uploadcsverrorwrongnumberoffields', 'admin', $i)); continue; } $shortname = $line[$formatkeylookup['shortname']]; $displayname = $line[$formatkeylookup['displayname']]; $grouptype = $line[$formatkeylookup['roles']]; $open = isset($formatkeylookup['open']) && !empty($line[$formatkeylookup['open']]); $controlled = isset($formatkeylookup['controlled']) && !empty($line[$formatkeylookup['controlled']]); $request = isset($formatkeylookup['request']) && !empty($line[$formatkeylookup['request']]); $submitpages = isset($formatkeylookup['submitpages']) && !empty($line[$formatkeylookup['submitpages']]); if (isset($formatkeylookup['editroles'])) { $editroles = $line[$formatkeylookup['editroles']]; } if (!preg_match('/^[a-zA-Z0-9_.-]{2,255}$/', $shortname)) { $csverrors->add($i, get_string('uploadgroupcsverrorinvalidshortname', 'admin', $i, $shortname)); } if (isset($shortnames[$shortname])) { // Duplicate shortname within this file. $csverrors->add($i, get_string('uploadgroupcsverrorshortnamealreadytaken', 'admin', $i, $shortname)); } else { if (!$values['updategroups']) { // The groupname must be new if (record_exists('group', 'shortname', $shortname, 'institution', $institution)) { $csverrors->add($i, get_string('uploadgroupcsverrorshortnamealreadytaken', 'admin', $i, $shortname)); } } else { if ($values['updategroups']) { // The groupname needs to exist if (!record_exists('group', 'shortname', $shortname, 'institution', $institution)) { $csverrors->add($i, get_string('uploadgroupcsverrorshortnamemissing', 'admin', $i, $shortname)); } } } } $shortnames[$shortname] = array('shortname' => $shortname, 'displayname' => $displayname, 'roles' => $grouptype, 'lineno' => $i, 'raw' => $line); if (isset($displaynames[strtolower($displayname)])) { // Duplicate displayname within this file $csverrors->add($i, get_string('uploadgroupcsverrorsgroupnamealreadyexists', 'admin', $i, $displayname)); } else { if (!$values['updategroups']) { // The displayname must be new if (get_records_sql_array('SELECT id FROM {group} WHERE LOWER(TRIM(name)) = ?', array(strtolower(trim($displayname))))) { $csverrors->add($i, get_string('uploadgroupcsverrorgroupnamealreadyexists', 'admin', $i, $displayname)); } } else { // This displayname must be new if not our shortname/institution if (get_records_sql_array(' SELECT id FROM {group} WHERE LOWER(TRIM(name)) = ? AND NOT (shortname = ? AND institution = ?)', array(strtolower(trim($displayname)), $shortname, $institution))) { $csverrors->add($i, get_string('uploadgroupcsverrorgroupnamealreadyexists', 'admin', $i, $displayname)); } } } $displaynames[strtolower($displayname)] = 1; if (!isset($GROUPTYPES[$grouptype])) { $csverrors->add($i, get_string('uploadgroupcsverrorinvalidgrouptype', 'admin', $i, $grouptype)); } if (isset($editroles) && !isset($EDITROLES[$editroles])) { $csverrors->add($i, get_string('uploadgroupcsverrorinvalideditroles', 'admin', $i, $editroles)); } if ($open && $controlled) { $csverrors->add($i, get_string('uploadgroupcsverroropencontrolled', 'admin', $i)); } if ($open && $request) { $csverrors->add($i, get_string('uploadgroupcsverroropenrequest', 'admin', $i)); } if ($values['updategroups']) { foreach ($shortnames as $shortname => $data) { // TODO: Any other checks we have to do for updated groups $UPDATES[$shortname] = 1; } } } if ($errors = $csverrors->process()) { $form->set_error('file', clean_html($errors)); return; } $FORMAT = $csvdata->format; $CSVDATA = $csvdata->data; }
/** * Renders form elements inside a <table>. * * @param Pieform $form The form the element is being rendered for * @param string $element The element to be rendered * @return string The element rendered inside an appropriate container */ function pieform_renderer_maharatable(Pieform $form, $element) { $formname = $form->get_name(); if ($element['type'] == 'fieldset') { // Add table tags to the build element, to preserve HTML compliance $builtelement = $element['html']; if (0 === strpos($builtelement, "\n<fieldset")) { $closelegendpos = strpos($builtelement, '</legend>'); if ($closelegendpos !== false) { $closelegendpos += 9; $builtelement = substr($builtelement, 0, $closelegendpos) . '<table>' . substr($builtelement, $closelegendpos); } else { $pos = strpos($builtelement, '>') + 1; $builtelement = substr($builtelement, 0, $pos) . '<table>' . substr($builtelement, $pos); } } else { $builtelement = substr($builtelement, 0, 11) . '<table>' . substr($builtelement, 11); } $builtelement = substr($builtelement, 0, -12) . '</table></fieldset>'; $result = "\t<tr>\n\t\t<td colspan=\"2\">"; $result .= $builtelement; $result .= "</td>\n\t</tr>"; return $result; } $result = ''; if (isset($element['labelhtml']) && $element['labelhtml'] !== '') { $result .= "\t<tr"; $result .= ' id="' . $formname . '_' . $element['name'] . '_header"'; // Set the class of the enclosing <tr> to match that of the element if ($element['class']) { $result .= ' class="' . $element['class'] . '"'; } $result .= ">\n\t\t"; $result .= '<th>'; $result .= $element['labelhtml']; $result .= "</th>\n\t</tr>\n"; } $result .= "\t<tr id=\"{$formname}_{$element['name']}_container\">\n\t\t<td>"; // Wrap WYSIWYG elements in a table with two cells side by side, one for the element and one for the help icon if (!empty($element['help']) && $element['type'] == 'wysiwyg') { $result .= '<table class="help-wrapper"><tr><td>'; } // Add the element itself $result .= $element['html']; if (!empty($element['help']) && $element['type'] == 'wysiwyg') { $result .= '</td><td>'; } // Contextual help if (!empty($element['help'])) { $result .= get_help_icon($form->get_property('plugintype'), $form->get_property('pluginname'), $form->get_name(), $element['name']); if ($element['type'] == 'wysiwyg') { $result .= '</td></tr></table>'; } } $result .= "</td>\n\t</tr>\n"; // Description - optional description of the element, or other note that should be visible // on the form itself (without the user having to hover over contextual help if ((!$form->has_errors() || $form->get_property('showdescriptiononerror')) && !empty($element['description'])) { $result .= "\t<tr>\n\t\t<td class=\"description\">"; $result .= $element['description']; $result .= "</td>\n\t</tr>\n"; } if (!empty($element['error'])) { $result .= "\t<tr>\n\t\t<td class=\"errmsg\">"; $result .= $element['error']; $result .= "</td>\n\t</tr>\n"; } return $result; }
/** * The CSV file is parsed here so validation errors can be returned to the * user. The data from a successful parsing is stored in the <var>$CVSDATA</var> * array so it can be accessed by the submit function * * @param Pieform $form The form to validate * @param array $values The values submitted */ function uploadcsv_validate(Pieform $form, $values) { global $CSVDATA, $ALLOWEDKEYS, $FORMAT, $USER; // Don't even start attempting to parse if there are previous errors if ($form->has_errors()) { return; } if ($values['file']['size'] == 0) { $form->set_error('file', $form->i18n('rule', 'required', 'required', array())); return; } require_once 'pear/File.php'; require_once 'pear/File/CSV.php'; // Don't be tempted to use 'explode' here. There may be > 1 underscore. $break = strpos($values['authinstance'], '_'); $authinstance = substr($values['authinstance'], 0, $break); $institution = substr($values['authinstance'], $break + 1); if (!$USER->can_edit_institution($institution)) { $form->set_error('authinstance', get_string('notadminforinstitution', 'admin')); return; } $usernames = array(); $emails = array(); $conf = File_CSV::discoverFormat($values['file']['tmp_name']); $i = 0; while ($line = File_CSV::readQuoted($values['file']['tmp_name'], $conf)) { $i++; if (!is_array($line)) { // Note: the CSV parser returns true on some errors and false on // others! Yes that's retarded. No I didn't write it :( $form->set_error('file', get_string('uploadcsverrorincorrectnumberoffields', 'admin', $i)); return; } // Get the format of the file if ($i == 1) { foreach ($line as &$potentialkey) { $potentialkey = trim($potentialkey); if (!in_array($potentialkey, $ALLOWEDKEYS)) { $form->set_error('file', get_string('uploadcsverrorinvalidfieldname', 'admin', $potentialkey)); return; } } // Now we know all of the field names are valid, we need to make // sure that the required fields are included $mandatoryfields = array('username', 'password'); $mandatoryfields = array_merge($mandatoryfields, array_keys(ArtefactTypeProfile::get_mandatory_fields())); if ($lockedprofilefields = get_column('institution_locked_profile_field', 'profilefield', 'name', $institution)) { $mandatoryfields = array_merge($mandatoryfields, $lockedprofilefields); } // Add in the locked profile fields for this institution foreach ($mandatoryfields as $field) { if (!in_array($field, $line)) { $form->set_error('file', get_string('uploadcsverrorrequiredfieldnotspecified', 'admin', $field)); return; } } // The format line is valid $FORMAT = $line; log_info('FORMAT:'); log_info($FORMAT); } else { // Trim non-breaking spaces -- they get left in place by File_CSV foreach ($line as &$field) { $field = preg_replace('/^(\\s|\\xc2\\xa0)*(.*?)(\\s|\\xc2\\xa0)*$/', '$2', $field); } // We have a line with the correct number of fields, but should validate these fields // Note: This validation should really be methods on each profile class, that way // it can be used in the profile screen as well. $formatkeylookup = array_flip($FORMAT); $username = $line[$formatkeylookup['username']]; $password = $line[$formatkeylookup['password']]; $email = $line[$formatkeylookup['email']]; $authobj = AuthFactory::create($authinstance); if (method_exists($authobj, 'is_username_valid') && !$authobj->is_username_valid($username)) { $form->set_error('file', get_string('uploadcsverrorinvalidusername', 'admin', $i)); return; } if (record_exists_select('usr', 'LOWER(username) = ?', strtolower($username)) || isset($usernames[strtolower($username)])) { $form->set_error('file', get_string('uploadcsverroruseralreadyexists', 'admin', $i, $username)); return; } if (record_exists('usr', 'email', $email) || isset($emails[$email])) { $form->set_error('file', get_string('uploadcsverroremailaddresstaken', 'admin', $i, $email)); } // Note: only checks for valid form are done here, none of the checks // like whether the password is too easy. The user is going to have to // change their password on first login anyway. if (method_exists($authobj, 'is_password_valid') && !$authobj->is_password_valid($password)) { $form->set_error('file', get_string('uploadcsverrorinvalidpassword', 'admin', $i)); return; } $usernames[strtolower($username)] = 1; $emails[$email] = 1; // All OK! $CSVDATA[] = $line; } } if ($i == 1) { // There was only the title row :( $form->set_error('file', get_string('uploadcsverrornorecords', 'admin')); return; } if ($CSVDATA === null) { // Oops! Couldn't get CSV data for some reason $form->set_error('file', get_string('uploadcsverrorunspecifiedproblem', 'admin')); } }