/** * Reads a "row" from a CSV file and return it as an array * * @param string $file The CSV file * @param array &$conf The configuration of the dest CSV * * @return mixed Array or false */ function read($file, &$conf) { static $headers = array(); if (!($fp = File_CSV::getPointer($file, $conf, FILE_MODE_READ))) { return false; } // The size is limited to 4K if (!($line = fgets($fp, 4096))) { return false; } $fields = $conf['fields'] == 1 ? array($line) : explode($conf['sep'], $line); $nl = array("\n", "\r", "\r\n"); if (in_array($fields[count($fields) - 1], $nl)) { array_pop($fields); } $field_count = count($fields); $last =& $fields[$field_count - 1]; $len = strlen($last); if ($field_count != $conf['fields'] || $conf['quote'] && ($len !== 0 && $last[$len - 1] == "\n" && ($last[0] == $conf['quote'] && $last[strlen(rtrim($last)) - 1] != $conf['quote'] || $last[0] == '=' && $last[1] == $conf['quote'] || preg_match('|^\\s+' . preg_quote($conf['quote']) . '|Ums', $last, $match)))) { fseek($fp, -1 * strlen($line), SEEK_CUR); return File_CSV::readQuoted($file, $conf); } foreach ($fields as $k => $v) { $fields[$k] = File_CSV::unquote($v, $conf['quote']); } if (isset($conf['header']) && empty($headers)) { // read the first row and assign to $headers $headers = $fields; return $headers; } if ($field_count != $conf['fields']) { File_CSV::raiseError("Read wrong fields number count: '" . $field_count . "' expected " . $conf['fields']); return true; } if (!empty($headers)) { $tmp = array(); foreach ($fields as $k => $v) { $tmp[$headers[$k]] = $v; } $fields = $tmp; } return $fields; }
/** * Reads a "row" from a CSV file and return it as an array * * @param string $file The CSV file * @param array &$conf The configuration of the dest CSV * * @return mixed Array or false */ function read($file, &$conf) { if (!($fp = File_CSV::getPointer($file, $conf, FILE_MODE_READ))) { return false; } // The size is limited to 4K if (!($line = fgets($fp, 4096))) { return false; } $fields = explode($conf['sep'], $line); if ($conf['quote']) { $last =& $fields[count($fields) - 1]; // Fallback to read the line with readQuoted when guess // that the simple explode won't work right if ($last[strlen($last) - 1] == "\n" && $last[0] == $conf['quote'] && $last[strlen(rtrim($last)) - 1] != $conf['quote'] || count($fields) != $conf['fields']) { $len = strlen($line); fseek($fp, -1 * strlen($line), SEEK_CUR); return File_CSV::readQuoted($file, $conf); } else { $last = rtrim($last); foreach ($fields as $k => $v) { $fields[$k] = File_CSV::unquote($v, $conf['quote']); } } } if (count($fields) != $conf['fields']) { File_CSV::raiseError("Read wrong fields number count: '" . count($fields) . "' expected " . $conf['fields']); return true; } return $fields; }
/** * 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')); } }
/** * Reads a "row" from a CSV file and return it as an array * * @param string $file The CSV file * @param array &$conf The configuration of the dest CSV * * @return mixed Array or false */ function read($file, &$conf) { if (!($fp = File_CSV::getPointer($file, $conf, FILE_MODE_READ))) { return false; } // The size is limited to 4K if (!($line = fgets($fp, 4096))) { return false; } if ($conf['fields'] === 1) { $fields = array($line); $field_count = 1; } else { $fields = explode($conf['sep'], $line); $field_count = count($fields); } $real_field_count = $field_count - 1; $check_char = $fields[$real_field_count]; if ($check_char === "\n" || $check_char === "\r") { array_pop($fields); --$field_count; } $last =& $fields[$real_field_count]; if ($field_count !== $conf['fields'] || $conf['quote'] && ($last !== '' && ($last[0] === $conf['quote'] && $last[strlen(rtrim($last)) - 1] !== $conf['quote'] || $last[0] === '=' && $last[1] === $conf['quote'])) || count(explode(',', $line)) > $field_count) { fseek($fp, -1 * strlen($line), SEEK_CUR); $fields = File_CSV::readQuoted($file, $conf); $fields = File_CSV::_processHeaders($fields, $conf); return $fields; } $fields = File_CSV::unquote($fields, $conf['quote']); if ($field_count != $conf['fields']) { File_CSV::raiseError("Read wrong fields number count: '" . $field_count . "' expected " . $conf['fields']); return true; } $fields = File_CSV::_processHeaders($fields, $conf); return $fields; }
/** * Reads a "row" from a CSV file and return it as an array * * @param string $file The CSV file * @param array &$conf The configuration of the dest CSV * * @return mixed Array or false */ function read($file, &$conf) { static $headers = array(); if (!($fp = File_CSV::getPointer($file, $conf, FILE_MODE_READ))) { return false; } // The size is limited to 4K if (!($line = fgets($fp, 4096))) { return false; } if ($conf['fields'] === 1) { $fields = array($line); $field_count = 1; } else { $fields = explode($conf['sep'], $line); $field_count = count($fields); while ($field_count < $conf['fields']) { if (!($additional_line = fgets($fp, 4096))) { return false; } $line .= $additional_line; $fields = explode($conf['sep'], $line); $field_count = count($fields); } } $real_field_count = $field_count - 1; $check_char = $fields[$real_field_count]; if ($check_char === "\n" || $check_char === "\r") { array_pop($fields); --$field_count; } $last =& $fields[$real_field_count]; if ($field_count !== $conf['fields'] || $conf['quote'] && ($last !== '' && ($last[0] === $conf['quote'] && $last[strlen(rtrim($last)) - 1] !== $conf['quote'] || $last[0] === '=' && $last[1] === $conf['quote'])) || count(explode(',', $line)) > $field_count) { fseek($fp, -1 * strlen($line), SEEK_CUR); return File_CSV::readQuoted($file, $conf); } $fields = File_CSV::unquote($fields, $conf['quote']); if (isset($conf['header']) && empty($headers)) { // read the first row and assign to $headers $headers = $fields; return $headers; } if ($field_count != $conf['fields']) { File_CSV::raiseError("Read wrong fields number count: '" . $field_count . "' expected " . $conf['fields']); return true; } if (!empty($headers)) { $tmp = array(); foreach ($fields as $k => $v) { $tmp[$headers[$k]] = $v; } $fields = $tmp; } return $fields; }