filehandle = fopen($filename, 'r')) !== false) {
return;
}
}
$this->errors['file'] = get_string('invalidfilename', 'admin', $filename);
}
public function get($field) {
if (!property_exists($this, $field)) {
throw new InvalidArgumentException("Field $field wasn't found in class " . get_class($this));
}
return $this->{$field};
}
public function set($field, $value) {
if (property_exists($this, $field)) {
if ($this->{$field} != $value) {
// only set it to dirty if it's changed
$this->dirty = true;
}
$this->{$field} = $value;
if ($field == 'parent') {
$this->parentdirty = true;
}
$this->mtime = time();
return true;
}
throw new InvalidArgumentException("Field $field wasn't found in class " . get_class($this));
}
public function get_data() {
$csvfile = new StdClass;
if (!empty($this->errors)) {
$csvfile->errors = $this->errors;
return $csvfile;
}
$this->parse_data();
if ($this->filehandle !== false) {
fclose($this->filehandle);
}
$csvfile->errors = $this->errors;
if (empty($this->format) && empty($this->errors)) {
throw new SystemException('CSV File has no headers');
}
else {
$csvfile->format = $this->format;
}
$csvfile->data = $this->data;
return $csvfile;
}
public function add_error($key, $value) {
$this->errors[$key] = $value;
}
private function parse_data() {
if (false === $this->filehandle) {
return; // file is not open
}
$delimiter = $this->detectDelimiter();
$i = 0;
while (($line = fgetcsv($this->filehandle, MAX_LINE_LENGTH, $delimiter)) !== false) {
$i++;
// Get the format of the file
if ($this->headerExists && $i == 1) {
foreach ($line as &$potentialkey) {
$potentialkey = trim($potentialkey);
if (!in_array($potentialkey, $this->allowedkeys)) {
$this->add_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
foreach ($this->mandatoryfields as $field) {
if (!in_array($field, $line)) {
$this->add_error('file', get_string('uploadcsverrorrequiredfieldnotspecified', 'admin', $field));
return;
}
}
// The format line is valid
$this->format = $line;
log_info('FORMAT:');
log_info($this->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);
}
// All OK!
$this->data[] = $line;
}
}
if ($this->headerExists && $i == 1) {
// There was only the title row :(
$this->add_error('file', get_string('uploadcsverrornorecords', 'admin'));
return;
}
if ($this->data === null) {
// Oops! Couldn't get CSV data for some reason
$this->add_error('file', get_string('uploadcsverrorunspecifiedproblem1', 'admin'));
}
}
/**
* detect the delimiter using the first line that should consist only of
* the header fields, which strictly consist of the characters [a-zA-Z0-9_]
* so the known delimiters (so far comma and semicolon) don't appear in those
* fields.
* Background is that Microsoft separates the fields in csv-files with
* semicolons when the System language is set to German
* @return string the delimiter used to separate the fields in the file
*/
private function detectDelimiter() {
static $knowndelimiters = array(
',',
';',
':',
"\t",
' '
);
$firstline = fgets($this->filehandle);
fseek($this->filehandle, 0);
foreach ($knowndelimiters as $delimiter) {
if (strpos($firstline, $delimiter) > 0) {
return $delimiter;
}
}
// Default: the comma. In case we have a file with only one field per
// line, we cannot detect the delimiter. Luckily Mahara always expects
// more than one mandatory fields, so getting here usually means the
// file cannot be imported anyway
return ',';
}
}
class CSVErrors {
private $csverrors = array();
function add($line, $msg) {
if (!isset($this->csverrors[$line])) {
$this->csverrors[$line] = array();
}
$this->csverrors[$line][] = $msg;
}
function process() {
if (empty($this->csverrors)) {
return;
}
ksort($this->csverrors);
$errorstring = implode("
\n", array_shift($this->csverrors));
while ($lineerrors = array_shift($this->csverrors)) {
$errorstring .= "
\n" . implode("
\n", $lineerrors);
}
return $errorstring;
}
}