Permalink
Browse files

MDL-34074 - lib - Creation of a csv upload class which is FRC 4180 co…

…mpliant and the alteration of various files around Moodle to use this class.
  • Loading branch information...
1 parent 55a568f commit 9a5abd1b709d73dfe8df4fcc325b90f2eee24375 @abgreeve abgreeve committed Jul 27, 2012
Showing with 319 additions and 93 deletions.
  1. +16 −17 admin/user/user_bulk_download.php
  2. +15 −37 grade/export/txt/grade_export_txt.php
  3. +191 −0 lib/csvlib.class.php
  4. +15 −14 lib/tablelib.php
  5. +75 −0 lib/tests/csvclass_test.php
  6. +7 −25 mod/data/lib.php
@@ -148,34 +148,33 @@ function user_download_csv($fields) {
global $CFG, $SESSION, $DB;
require_once($CFG->dirroot.'/user/profile/lib.php');
+ require_once($CFG->libdir . '/csvlib.class.php');
- $filename = clean_filename(get_string('users').'.csv');
+ $filename = clean_filename(get_string('users'));
- header("Content-Type: application/download\n");
- header("Content-Disposition: attachment; filename=\"$filename\"");
- header("Expires: 0");
- header("Cache-Control: must-revalidate,post-check=0,pre-check=0");
- header("Pragma: public");
-
- $delimiter = get_string('listsep', 'langconfig');
- $encdelim = '&#'.ord($delimiter);
-
- $row = array();
- foreach ($fields as $fieldname) {
- $row[] = str_replace($delimiter, $encdelim, $fieldname);
- }
- echo implode($delimiter, $row)."\n";
+ $csvexport = new csv_export_writer();
+ $csvexport->set_filename($filename);
+ $csvexport->add_data($fields);
foreach ($SESSION->bulk_users as $userid) {
$row = array();
if (!$user = $DB->get_record('user', array('id'=>$userid))) {
continue;
}
profile_load_data($user);
+ $userprofiledata = array();
foreach ($fields as $field=>$unused) {
- $row[] = str_replace($delimiter, $encdelim, $user->$field);
+ // Custom user profile textarea fields come in an array
+ // The first element is the text and the second is the format.
+ // We only take the text.
+ if (is_array($user->$field)) {
+ $userprofiledata[] = reset($user->$field);
+ } else {
+ $userprofiledata[] = $user->$field;
+ }
}
- echo implode($delimiter, $row)."\n";
+ $csvexport->add_data($userprofiledata);
}
+ $csvexport->download_file();
die;
}
@@ -16,6 +16,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
require_once($CFG->dirroot.'/grade/export/lib.php');
+require_once($CFG->libdir . '/csvlib.class.php');
class grade_export_txt extends grade_export {
@@ -54,46 +55,25 @@ public function print_grades() {
$strgrades = get_string('grades');
$profilefields = grade_helper::get_user_profile_fields($this->course->id, $this->usercustomfields);
- switch ($this->separator) {
- case 'comma':
- $separator = ",";
- break;
- case 'tab':
- default:
- $separator = "\t";
- }
-
- // Print header to force download
- if (strpos($CFG->wwwroot, 'https://') === 0) { //https sites - watch out for IE! KB812935 and KB316431
- @header('Cache-Control: max-age=10');
- @header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT');
- @header('Pragma: ');
- } else { //normal http - prevent caching at all cost
- @header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0');
- @header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT');
- @header('Pragma: no-cache');
- }
- header("Content-Type: application/download\n");
$shortname = format_string($this->course->shortname, true, array('context' => context_course::instance($this->course->id)));
$downloadfilename = clean_filename("$shortname $strgrades");
- header("Content-Disposition: attachment; filename=\"$downloadfilename.txt\"");
+ $csvexport = new csv_export_writer($this->separator);
+ $csvexport->set_filename($downloadfilename);
// Print names of all the fields
- $fieldfullnames = array();
+ $exporttitle = array();
foreach ($profilefields as $field) {
- $fieldfullnames[] = $field->fullname;
+ $exporttitle[] = $field->fullname;
}
- echo implode($separator, $fieldfullnames);
+ // Add a feedback column.
foreach ($this->columns as $grade_item) {
- echo $separator.$this->format_column_name($grade_item);
-
- // Add a feedback column.
+ $exporttitle[] = $this->format_column_name($grade_item);
if ($this->export_feedback) {
- echo $separator.$this->format_column_name($grade_item, true);
+ $exporttitle[] = $this->format_column_name($grade_item, true);
}
}
- echo "\n";
+ $csvexport->add_data($exporttitle);
// Print all the lines of data.
$geub = new grade_export_update_buffer();
@@ -103,31 +83,29 @@ public function print_grades() {
$gui->init();
while ($userdata = $gui->next_user()) {
+ $exportdata = array();
$user = $userdata->user;
- $items = array();
foreach ($profilefields as $field) {
$fieldvalue = grade_helper::get_user_field_value($user, $field);
- $items[] = $fieldvalue;
+ $exportdata[] = $fieldvalue;
}
- echo implode($separator, $items);
-
foreach ($userdata->grades as $itemid => $grade) {
if ($export_tracking) {
$status = $geub->track($grade);
}
- echo $separator.$this->format_grade($grade);
+ $exportdata[] = $this->format_grade($grade);
if ($this->export_feedback) {
- echo $separator.$this->format_feedback($userdata->feedbacks[$itemid]);
+ $exportdata[] = $this->format_feedback($userdata->feedbacks[$itemid]);
}
}
- echo "\n";
+ $csvexport->add_data($exportdata);
}
$gui->close();
$geub->close();
-
+ $csvexport->download_file();
exit;
}
}
View
@@ -279,6 +279,7 @@ static function get_delimiter($delimiter_name) {
case 'tab': return "\t";
case 'cfg': if (isset($CFG->CSV_DELIMITER)) { return $CFG->CSV_DELIMITER; } // no break; fall back to comma
case 'comma': return ',';
+ default : return ','; // If anything else comes in, default to comma.
}
}
@@ -319,3 +320,193 @@ static function get_new_iid($type) {
return $iiid;
}
}
+
+/**
+ * Utitily class for exporting of CSV files.
+ * @copyright 2012 Adrian Greeve
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @package core
+ * @category csv
+ */
+class csv_export_writer {
+ /**
+ * @var string $delimiter The name of the delimiter. Supported types(comma, tab, semicolon, colon, cfg)
+ */
+ var $delimiter;
+ /**
+ * @var string $csvenclosure How fields with spaces and commas are enclosed.
+ */
+ var $csvenclosure;
+ /**
+ * @var string $mimetype Mimetype of the file we are exporting.
+ */
+ var $mimetype;
+ /**
+ * @var string $filename The filename for the csv file to be downloaded.
+ */
+ var $filename;
+ /**
+ * @var string $path The directory path for storing the temporary csv file.
+ */
+ var $path;
+ /**
+ * @var resource $fp File pointer for the csv file.
+ */
+ protected $fp;
+
+ /**
+ * Constructor for the csv export reader
+ *
+ * @param string $delimiter The name of the character used to seperate fields. Supported types(comma, tab, semicolon, colon, cfg)
+ * @param string $enclosure The character used for determining the enclosures.
+ * @param string $mimetype Mime type of the file that we are exporting.
+ */
+ public function __construct($delimiter = 'comma', $enclosure = '"', $mimetype = 'application/download') {
+ $this->delimiter = $delimiter;
+ // Check that the enclosure is a single character.
+ if (strlen($enclosure) == 1) {
+ $this->csvenclosure = $enclosure;
+ } else {
+ $this->csvenclosure = '"';
+ }
+ $this->filename = "Moodle-data-export.csv";
+ $this->mimetype = $mimetype;
+ }
+
+ /**
+ * Set the file path to the temporary file.
+ */
+ protected function set_temp_file_path() {
+ global $USER, $CFG;
+ make_temp_directory('csvimport/' . $USER->id);
+ $path = $CFG->tempdir . '/csvimport/' . $USER->id. '/' . $this->filename;
+ // Check to see if the file exists, if so delete it.
+ if (file_exists($path)) {
+ unlink($path);
+ }
+ $this->path = $path;
+ }
+
+ /**
+ * Add data to the temporary file in csv format
+ *
+ * @param array $row An array of values.
+ */
+ public function add_data($row) {
+ if(!isset($this->path)) {
+ $this->set_temp_file_path();
+ $this->fp = fopen($this->path, 'w+');
+ }
+ $delimiter = csv_import_reader::get_delimiter($this->delimiter);
+ fputcsv($this->fp, $row, $delimiter, $this->csvenclosure);
+ }
+
+ /**
+ * Echos or returns a csv data line by line for displaying.
+ *
+ * @param bool $return Set to true to return a string with the csv data.
+ * @return string csv data.
+ */
+ public function print_csv_data($return = false) {
+ fseek($this->fp, 0);
+ $returnstring = '';
+ while (($content = fgets($this->fp)) !== false) {
+ if (!$return){
+ echo $content;
+ } else {
+ $returnstring .= $content;
+ }
+ }
+ if ($return) {
+ return $returnstring;
+ }
+ }
+
+ /**
+ * Set the filename for the uploaded csv file
+ *
+ * @param string $dataname The name of the module.
+ * @param string $extenstion File extension for the file.
+ */
+ public function set_filename($dataname, $extension = '.csv') {
+ $filename = clean_filename($dataname);
+ $filename .= clean_filename('-' . gmdate("Ymd_Hi"));
+ $filename .= clean_filename("-{$this->delimiter}_separated");
+ $filename .= $extension;
+ $this->filename = $filename;
+ }
+
+ /**
+ * Output file headers to initialise the download of the file.
+ */
+ protected function send_header() {
+ global $CFG;
+ if (strpos($CFG->wwwroot, 'https://') === 0) { //https sites - watch out for IE! KB812935 and KB316431
+ header('Cache-Control: max-age=10');
+ header('Pragma: ');
+ } else { //normal http - prevent caching at all cost
+ header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0');
+ header('Pragma: no-cache');
+ }
+ header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT');
+ header("Content-Type: $this->mimetype\n");
+ header("Content-Disposition: attachment; filename=\"$this->filename\"");
+ }
+
+ /**
+ * Download the csv file.
+ */
+ public function download_file() {
+ $this->send_header();
+ $this->print_csv_data();
+ exit;
+ }
+
+ /**
+ * Creates a file for downloading an array into a deliminated format.
+ * This function is useful if you are happy with the defaults and all of your
+ * information is in one array.
+ *
+ * @param string $filename The filename of the file being created.
+ * @param array $records An array of information to be converted.
+ * @param string $delimiter The name of the delimiter. Supported types(comma, tab, semicolon, colon, cfg)
+ * @param string $enclosure How speical fields are enclosed.
+ */
+ public static function download_array($filename, array &$records, $delimiter = 'comma', $enclosure='"') {
+ $csvdata = new csv_export_writer($delimiter, $enclosure);
+ $csvdata->set_filename($filename);
+ foreach ($records as $row) {
+ $csvdata->add_data($row);
+ }
+ $csvdata->download_file();
+ }
+
+ /**
+ * This will convert an array of values into a deliminated string.
+ * Like the above function, this is for convenience.
+ *
+ * @param array $records An array of information to be converted.
+ * @param string $delimiter The name of the delimiter. Supported types(comma, tab, semicolon, colon, cfg)
+ * @param string $enclosure How speical fields are enclosed.
+ * @param bool $return If true will return a string with the csv data.
+ * @return string csv data.
+ */
+ public static function print_array(array &$records, $delimiter = 'comma', $enclosure = '"', $return = false) {
+ $csvdata = new csv_export_writer($delimiter, $enclosure);
+ foreach ($records as $row) {
+ $csvdata->add_data($row);
+ }
+ $data = $csvdata->print_csv_data($return);
+ if ($return) {
+ return $data;
+ }
+ }
+
+ /**
+ * Make sure that everything is closed when we are finished.
+ */
+ public function __destruct() {
+ fclose($this->fp);
+ unlink($this->path);
+ }
+}
Oops, something went wrong.

0 comments on commit 9a5abd1

Please sign in to comment.