Edit User Accounts page) // N.B. Using user account search strings instead of IDs gives a performance hit with a large number of teachers // I did not add Student enrolment, though this would be relatively trivial, as this is already // handled by the far more elegant enrolment plugin system. // Teachers are a sort of "course property", but Students are not. // Rory Allford (rory@allford.net) // 22nd June 2007 Mark Pearson (markp@earlham.edu) // minor tweaks to increase size of category (from 30 - 50) and shortname (from 15 to 20) // line 210 from (Category name "'.$item.'" length > 30) to (Category name "'.$item.'" length > 50) // line 629 from 'shortname' => array(1,15,1) to 'shortname' => array(1,20,1) // line 910 modify help to read shortname string(20) // ----------------------------------------------------------------------------------------------------- // UPDATED BY: Austin Gooding & Cole Spicer // UPDATE: Added compatability for newer versions of moodle as well as made future updates easier // Just add new mdl_course column names to $optional and $validate arrays. // DATE: 3/27/07 // ----------------------------------------------------------------------------------------------------- //error_reporting(E_ALL | E_STRICT ); // Some Regex constants define('TOPIC_FIELD','/^(topic)([0-9]|[1-4][0-9]|5[0-2])$/'); define('TEACHER_FIELD','/^(teacher)([1-9]+\d*)(_account|_role)$/'); require_once('../config.php'); require_once("../course/lib.php"); require_once("$CFG->libdir/blocklib.php"); $courseid=-1; function csverror($message, $link='') { global $CFG, $SESSION; print_header(get_string('error')); echo '
'; $message = clean_text($message); print_simple_box(''.$message.'', 'center', '', '#FFBBBB', 5, 'errorbox'); if (!$link) { if ( !empty($SESSION->fromurl) ) { $link = $SESSION->fromurl; unset($SESSION->fromurl); } else { $link = $CFG->wwwroot .'/'; } } print_continue($link); print_footer(); die; } function getdefaultcategory() { static $mysqlresource1; static $cat; global $CFG; global $USER; ($mysqlresource1=mysql_query('SELECT MIN(`id`) FROM `'.$CFG->prefix.'course_categories`')) or csverror('You have no category table!','uploadcourse.php?sesskey='.$USER->sesskey); if (mysql_num_rows($mysqlresource1)) { $cat = mysql_fetch_row($mysqlresource1); return $cat[0]; } else { return 1; // *SHOULD* be the Misc category? } } function checkisint($supposedint) { return ((string)intval($supposedint) == $supposedint) ? true : false; } function checkisstring($supposedstring) { $supposedstring = trim($supposedstring); // Is it just spaces? return (strlen($supposedstring) == 0) ? false : true; } function validateas($value, $validatename, $lineno, $fieldname = '') { // Validates each field based on information in the $validate array global $USER; global $validate; ($fieldname=='') and ($fieldname=$validatename); (isset($validate[$validatename])) or csverror('Coding Error: Unvalidated field type: "'.$validatename.'"','uploadcourse.php?sesskey='.$USER->sesskey); $format = $validate[$validatename]; switch($format[0]) { case 1: // String if (($maxlen = $format[1])!=0) // Max length? (strlen($value) <=$format[1]) or csverror('Invalid value for field '.$fieldname.' (length > '.$format[1].'). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); if ($format[2] == 1) // Not null? checkisstring($value) or csverror('Invalid value for field '.$fieldname.' (only spaces or missing). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); break; case 2: // Integer checkisint($value) or csverror('Invalid value for field '.$fieldname.' (not an integer). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); if (($max = $format[1])!=0) // Max value? ($value <= $max) or csverror('Invalid value for field '.$fieldname.' (> '.$max.'). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); $min = $format[2]; // Min value ($value >= $min) or csverror('Invalid value for field '.$fieldname.' (< '.$min.'). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); break; case 3: // Timestamp - validates and converts to Unix Time if (($value = strtotime($value)) < 1) csverror('Invalid value for field '.$fieldname.' (Bad Timestamp). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); break; case 4: // Domain $validvalues = explode(',',$format[1]); if (array_search($value,$validvalues)===false) csverror('Invalid value for field '.$fieldname.' (Must be one of {'.$format[1].'}). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); break; case 5: // Category if (checkisint($value)) { // It's a Category ID Number categoryexists_ex($value) or csverror('Invalid value for field '.$fieldname.' (No Category with ID '.$value.'). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); } elseif(checkisstring($value)) { // It's a Category Path string $value=trim(str_replace('\\','/',$value)," \t\n\r\0\x0B/"); // Clean path, ensuring all slashes are forward ones (strlen($value)>0) or csverror('Invalid value for field '.$fieldname.' (Path string not set). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); unset ($cats); $cats=explode('/',$value); // Break up path into array (count($cats)>0) or csverror('Invalid value for field '.$fieldname.' (Path string "'.$value.'" invalid - not delimited correctly). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); foreach ($cats as $n => $item) { // Validate the path $item=trim($item); // Remove whitespace (strlen($item) <= 50) or csverror('Invalid value for field '.$fieldname.' (Category name "'.$item.'" length > 50). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); checkisstring($item) or csverror('Invalid value for field '.$fieldname.' (Path string "'.$value.'" invalid - category name at position '.($n+1).' as shown is invalid). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); } $value=$cats; // Return the array unset ($cats); } else { csverror('Invalid value for field '.$fieldname.' (not an integer or string). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); } break; case 6: // User ID or Name (Search String) $value=trim($value); if (checkisint($value)) { // User ID userexists_ex($value) or csverror('Invalid value for field '.$fieldname.' (No User with ID '.$value.'). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); } elseif (checkisstring($value)) { // User Search String // Only PHP5 supports named arguments $usersearch=get_users_listing('lastaccess','ASC',0,99999,mysql_real_escape_string($value),'',''); if (isset($usersearch) and ($usersearch!==false) and is_array($usersearch) and (($ucount=count($usersearch))>0)) { ($ucount==1) or csverror('Invalid value for field '.$fieldname.' (Search string ambiguous; returned multiple ['.$ucount.'] results). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); reset($usersearch); $uid=key($usersearch); (checkisint($uid) && userexists_ex($uid)) or csverror('Invalid value for field '.$fieldname.' (Search string returned a nonexistent user ?!). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); $value=$uid; // Return found user id } else { csverror('Invalid value for field '.$fieldname.' (Search string returned no results). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); } } else { if ($format[2] == 1) // Not null? csverror('Invalid value for field '.$fieldname.' (only spaces or missing). '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); } break; default: csverror('Coding Error: Bad field validation type: "'.$fieldname.'"','uploadcourse.php?sesskey='.$USER->sesskey); break; } return $value; } function categoryexists_ex($categoryid) { // Does category with given id exist? global $CFG; static $mysqlresource1; if ($mysqlresource1=mysql_query('SELECT `id` FROM `'.$CFG->prefix.'course_categories` WHERE `id`='.mysql_real_escape_string($categoryid))){ return mysql_num_rows($mysqlresource1) ? true : false; } else { return false; } } function userexists_ex($userid) { // Does category with given id exist? global $CFG; static $mysqlresource1; if ($mysqlresource1=mysql_query('SELECT `id` FROM `'.$CFG->prefix.'user` WHERE `deleted` = 0 AND `id`='.mysql_real_escape_string($userid))){ return mysql_num_rows($mysqlresource1) ? true : false; } else { return false; } } function microtime_float() { // In case we don't have php5 list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } function mystr($value) { // Prepare $value for inclusion in SQL Query return '\''.mysql_real_escape_string($value).'\'';; } function fast_get_category_ex($hname, &$hstatus, $hparent=0) { // Find category with the given name and parentID, or create it, in both cases returning a category ID /* $hstatus: -1 : Failed to create category 1 : Existing category found 2 : Created new category successfully */ static $mysqlresource1; static $mysqlresource2; static $cat; static $cname; global $CFG; global $USER; $cname = mystr($hname); // Check if a category with the same name and parent ID already exists $mysqlresource1=mysql_query('SELECT `id` FROM `'.$CFG->prefix.'course_categories` WHERE `name` = '.$cname.' AND `parent` = '.$hparent); if (mysql_num_rows($mysqlresource1)) { $cat = mysql_fetch_row($mysqlresource1); $hstatus=1; return $cat[0]; } else { // Create it - moodle does set sortorder to 999, and doesn't use the description field if (!($mysqlresource2=mysql_query('INSERT INTO `'.$CFG->prefix.'course_categories` (`name`,`description`,`parent`,`sortorder`,`coursecount`,`visible`,`timemodified`) VALUES ('.$cname.',\'\','.$hparent.',999,0,1,0);'))) { // Failed! $hstatus=-1; return -1; } else { $hstatus=2; return mysql_insert_id(); } } } function fast_is_course($hshortname) { // Does a course with the given shortname exist? global $CFG; static $mysqlresource1; static $cshortname; $cshortname = mystr($hshortname); if ($mysqlresource1=mysql_query('SELECT `id` FROM `'.$CFG->prefix.'course` WHERE `ShortName`='.$cshortname)) { // Check shortname is unique before inserting if (mysql_num_rows($mysqlresource1)) { return true; } else { return false; } } else { return false; } } // Edited by Austin Gooding & Cole Spicer to fix problems with 1.7.1 and make easier to dynamically add new columns function fastcreatecourse_ex($hcategory, $course, $header, $validate) { if(!is_array($course) || !is_array($header) || !is_array($validate)) { return -2; } global $CFG; // declaring as static prevents object pointers being continually created and destroyed, saving time in theory static $courseid; static $mysqlresource1; static $mysqlresource2; static $mysqlresource3; static $mysqlresource4; static $dcomma; // Creating SQL for composite fields static $dtopics; static $dtopicno; static $dtopicname; static $dteachers; static $dteacherno; static $dteacherdata; // Dynamically Create Query Based on number of headings excluding Teacher[1,2,...] and Topic[1,2,...] // Added for increased functionality with newer versions of moodle // Author: Austin Gooding & Cole Spicer static $tempstring; $query = 'INSERT INTO `'.$CFG->prefix.'course` (`category`,'; foreach ($header as $i => $col) { $col = strtolower($col); if(preg_match(TOPIC_FIELD, $col) || preg_match(TEACHER_FIELD, $col) || $col == 'category') { continue; } $query = $query.'`'.$col.'`,'; } $query = $query.'`modinfo`) VALUES ('.$hcategory.','; foreach ($header as $i => $col) { $col = strtolower($col); if(preg_match(TOPIC_FIELD, $col) || preg_match(TEACHER_FIELD, $col) || $col == 'category') { continue; } if($col == 'expirythreshold') { $course[$col] = $course[$col]*86400; } $temparray = explode(',',$validate[$col][1]); if($validate[$col][0] == 1 || ($validate[$col][0] == 4 && !checkisint($temparray[0]) ) ) { //String or Domain with strings $query = $query.''.mystr($course[$col]).', '; } else { $query = $query.''.$course[$col].', '; } } $query = $query.' \'\');'; // End Dynamic Query if (!($mysqlresource2=mysql_query($query))) { return -2; } $courseid=mysql_insert_id(); $page = page_create_object(PAGE_COURSE_VIEW, $courseid); blocks_repopulate_page($page); // Setup blocks $dtopics=''; // String concatenation for topic INSERT $dcomma=false; // Should we add a comma before the next item? if (isset($course['topics'])) { // Any topic headings specified ? foreach($course['topics'] as $dtopicno => $dtopicname) if ($dtopicno <= $course['numsections']) { // Avoid overflowing topic headings if ($dcomma==true) { $dtopics.=','; } else { $dcomma=true; } $dtopics.='('.$courseid.','.mystr($dtopicno).','.mystr($dtopicname).',\'\',\'1\')'; } } if (!isset($course['topics'][0])) { // Ensure at least default topic section exists if ($dcomma==true) { $dtopics.=','; } else { $dcomma=true; } $dtopics.='(\''.$courseid.'\',\'0\',\'\',\'\',\'1\');'; } else { $dtopics.=';'; } if (!($mysqlresource3=mysql_query('INSERT INTO `'.$CFG->prefix.'course_sections` (`course`,`section`,`summary`,`sequence`,`visible`) VALUES '.$dtopics))) return -3; $dteachers=''; // String concatenation for topic INSERT $dcomma=false; // Should we add a comma before the next item? // SELECT id FROM mdl_role WHERE name = blah // use that id and change insert to: // mdl_role_assignments // roleid contextid userid timemodified modifierid enrol // courseshit 0 'manual' // If SELECT id... doesnt work (returns false or contians no items) then throw error $roleid; if (!$context = get_context_instance(CONTEXT_COURSE, $courseid)) { return -6; } if (isset($course['teachers_enrol']) && (count($course['teachers_enrol'])>0)) { // Any teachers specified? foreach($course['teachers_enrol'] as $dteacherno => $dteacherdata) { if (isset($dteacherdata['_account'])) { if ($dcomma==true) { $dteachers.=','; } else { $dcomma=true; } if(!($mysqlresource5 = mysql_query('SELECT `id` FROM `'.$CFG->prefix.'role` WHERE `shortname`=\''.$dteacherdata['_role'].'\';')) ) { return -5; } if(!mysql_num_rows($mysqlresource5)) { return -5; } $row = mysql_fetch_row($mysqlresource5); $dteachers.='('.$row[0].','.$context->id.','.$dteacherdata['_account'].','.$course['timecreated'].',0,\'manual\');'; } } if ($dteachers!='') { if (!($mysqlresource4=mysql_query('INSERT INTO `'.$CFG->prefix.'role_assignments` (`roleid`,`contextid`,`userid`,`timemodified`,`modifierid`,`enrol`) VALUES '.$dteachers))) return -4; } } return 1; } require_login(); if (!isadmin()) { csverror('You must be an administrator to edit courses in this way.'); } /* if (!confirm_sesskey()) { csverror(get_string('confirmsesskeybad', 'error')); } */ if (! $site = get_site()) { csverror('Could not find site-level course'); } if (!$adminuser = get_admin()) { csverror('Could not find site admin'); } set_time_limit(300); // Up the php timeout $time_start = microtime_float(); // Just for timing $stradministration = get_string('administration'); $strchoose = get_string('choose'); $struploadcourses = 'Upload Courses'; $csv_encode = '/\&\#44/'; if (isset($CFG->CSV_DELIMITER)) { $csv_delimiter = '\\' . $CFG->CSV_DELIMITER; $csv_delimiter2 = $CFG->CSV_DELIMITER; if (isset($CFG->CSV_ENCODE)) { $csv_encode = '/\&\#' . $CFG->CSV_ENCODE . '/'; } } else { $csv_delimiter = '\,'; $csv_delimiter2 = ','; } /// Print the header print_header("$site->shortname: $struploadcourses", $site->fullname, "$stradministration -> $struploadcourses"); /// If a file has been uploaded, then process it require_once($CFG->dirroot.'/lib/uploadlib.php'); $um = new upload_manager('coursefile',false,false,null,false,0); if ($um->preprocess_files()) { if (!isset($um->files['coursefile'])) csverror('Upload Error!', 'uploadcourse.php?sesskey='.$USER->sesskey); $filename = $um->files['coursefile']['tmp_name']; // Everything to Unix Line Endings $text = my_file_get_contents($filename); $text = preg_replace('!\r\n?!',"\n",$text); if ($fp = fopen($filename, "w")) { fwrite($fp,$text); unset($text); // Memory! fclose($fp); } else { csverror('File I/O Error! (1)', 'uploadcourse.php?sesskey='.$USER->sesskey); } if (!$fp = fopen($filename, "r")) { csverror('File I/O Error! (2)', 'uploadcourse.php?sesskey='.$USER->sesskey); } // make arrays of fields for error checking $defaultcategory = getdefaultcategory(); $defaultmtime = time(); $required = array( 'fullname' => false, // Mandatory fields 'shortname' => false); $optional = array( 'category' => $defaultcategory, // Default values for optional fields 'sortorder' => 0, 'summary' => 'Write a concise and interesting paragraph here that explains what this course is about', 'format' => 'weeks', 'showgrades' => 0, 'newsitems' => 5, 'teacher' => 'Teacher', 'teachers' => 'Teachers', 'student' => 'Student', 'students' => 'Students', 'startdate' => $defaultmtime, 'numsections' => 16, 'maxbytes' => 2097152, 'visible' => 1, 'groupmode' => 0, 'timecreated' => $defaultmtime, 'timemodified' => $defaultmtime, 'idnumber' => '', 'password' => '', 'enrolperiod' => 0, 'groupmodeforce' => 0, 'metacourse' => 0, 'lang' => '', 'theme' => '', 'cost' => '', 'showreports' => 0, 'guest' => 0, 'enrollable' => 1, 'enrolstartdate' => $defaultmtime, 'enrolenddate' => $defaultmtime, 'notifystudents' => 0, 'expirynotify' => 0, 'expirythreshold' => 10); $validate = array( 'fullname' => array(1,254,1), // Validation information - see validateas function 'shortname' => array(1,20,1), 'category' => array(5), 'sortorder' => array(2,4294967295,0), 'summary' => array(1,0,0), 'format' => array(4,'social,topics,weeks'), 'showgrades' => array(4,'0,1'), 'newsitems' => array(2,10,0), 'teacher' => array(1,100,1), 'teachers' => array(1,100,1), 'student' => array(1,100,1), 'students' => array(1,100,1), 'startdate' => array(3), 'numsections' => array(2,52,0), 'maxbytes' => array(2,$CFG->maxbytes,0), 'visible' => array(4,'0,1'), 'groupmode' => array(4,NOGROUPS.','.SEPARATEGROUPS.','.VISIBLEGROUPS), 'timecreated' => array(3), 'timemodified' => array(3), 'idnumber' => array(1,100,0), 'password' => array(1,50,0), 'enrolperiod' => array(2,4294967295,0), 'groupmodeforce' => array(4,'0,1'), 'metacourse' => array(4,'0,1'), 'lang' => array(1,50,0), 'theme' => array(1,50,0), 'cost' => array(1,10,0), 'showreports' => array(4,'0,1'), 'guest' => array(4,'0,1,2'), 'enrollable' => array(4,'0,1'), 'enrolstartdate' => array(3), 'enrolenddate' => array(3), 'notifystudents' => array(4,'0,1'), 'expirynotify' => array(4,'0,1'), 'expirythreshold' => array(2,30,1), // Following ones cater for [something]N 'topic' => array(1,0,0), 'teacher_account' => array(6,0), 'teacher_role' => array(1,40,0)); $header = fgetcsv($fp, 1024); // check for valid field names if (($header[0]==null)&&(count($line)<1)) // Blank Line? csverror('First line must be the CSV header', 'uploadcourse.php?sesskey='.$USER->sesskey); foreach ($header as $i => $h) { if ($h==null) csverror('Null CSV columns are not permitted in header', 'uploadcourse.php?sesskey='.$USER->sesskey); if (preg_match(TOPIC_FIELD,$h)) { // Regex defined header names } elseif (preg_match(TEACHER_FIELD,$h)) { } else { if (!(isset($required[$h]) || isset($optional[$h]))) csverror(get_string('invalidfieldname', 'error', $h), 'uploadcourse.php?sesskey='.$USER->sesskey); if (isset($required[$h])) $required[$h] = true; // Mark Field as present } } // check for required fields foreach ($required as $key => $value) { if ($value != true) csverror(get_string('fieldrequired', 'error', $key), 'uploadcourse.php?sesskey='.$USER->sesskey); } $fieldcount = count($header); $lineno=2; unset($bulkcourses); while (($line = fgetcsv($fp, 1024)) !== false) { if (($line[0]!=null)||(count($line)>1)) { // Blank Line? if (count($line) > $fieldcount) csverror('Too many actual values. '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); foreach ($header as $i => $h) { // Is line complete? if (!isset($line[$i])) { csverror(get_string('missingfield', 'error', $h). ". ". get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); } } unset($coursetocreate); unset($coursetopics); unset($courseteachers); foreach ($optional as $key => $value) { // Set course array to defaults $coursetocreate[$key] = $value; } foreach ($line as $key => $value) { // Validate each value $cf = $header[$key]; if (preg_match(TOPIC_FIELD,$cf,$matches)) { $coursetopics[$matches[2]] = validateas($value,$matches[1], $lineno, $cf); } elseif (preg_match(TEACHER_FIELD,$cf,$matches)) { $tmp=validateas($value,$matches[1].$matches[3], $lineno, $cf); (isset($tmp)&&($tmp!='')) and ($courseteachers[$matches[2]][$matches[3]] = $tmp); } else { $coursetocreate[$cf] = validateas($value, $cf, $lineno); // Accept value if it passed validation } } $coursetocreate['topics'] = $coursetopics; if (isset($courseteachers)) foreach ($courseteachers as $key => $value) // Deep validate course teacher info on second pass { if (isset($value) && (count($value) > 0)){ if (!(isset($value['_account'])&&checkisint($value['_account']))) csverror('Invalid value for field teacher'.$key.' - other fields were specified but required teacher'.$key.'_account was null. '. get_string('erroronline', 'error', $lineno) .". ". get_string('processingstops', 'error'), 'uploadcourse.php?sesskey='.$USER->sesskey); // Hardcoded default values (that are as close to moodle's UI as possible) // and we can't assume PHP5 so no pointers! if (!isset($value['_role'])) $courseteachers[$key]['_role'] = ''; } } $coursetocreate['teachers_enrol'] = $courseteachers; $bulkcourses[] = $coursetocreate; // Merge into array } $lineno++; } fclose($fp); if ((!isset($bulkcourses)) or (count($bulkcourses)==0)) csverror('No courses were parsed from CSV', 'uploadcourse.php?sesskey='.$USER->sesskey); else notify('Parsed '.count($bulkcourses).' course(s) from CSV','notifysuccess'); // Running Status Totals $t = 0; // Read courses $s = 0; // Skipped courses $n = 0; // Created courses $p = 0; // Broken courses (failed halfway through $cat_e = 0; // Errored categories $cat_c = 0; // Created categories foreach ($bulkcourses as $bulkcourse) { // Try to create the course if (!fast_is_course($bulkcourse['shortname'])) { $coursetocategory = 0; // Category ID if (is_array($bulkcourse['category'])) { // Course Category creation routine as a category path was given $curparent=0; $curstatus=0; foreach ($bulkcourse['category'] as $catindex => $catname) { $curparent = fast_get_category_ex($catname,$curstatus,$curparent); switch ($curstatus) { case 1: // Skipped the category, already exists break; case 2: // Created a category $cat_c++; break; default: $cat_e+=count($bulkcourse['category']) - $catindex; $coursetocategory=-1; notify('An error occured creating category with name '.$catname.', meaning a total '.(count($bulkcourse['category']) - $catindex).' category(ies) failed','notifyproblem'); break 2; } } ($coursetocategory==-1) or $coursetocategory = $curparent; // Last category created will contain the actual course } else { // It's just a straight category ID $coursetocategory=$bulkcourse['category']; } if ($coursetocategory==-1) { notify('Course with ShortName '.$bulkcourse['shortname'].' could not be created because parent category(ies) failed','notifyproblem'); } else { //switch (fastcreatecourse_ex($coursetocategory, $bulkcourse['sortorder'], $bulkcourse['fullname'], $bulkcourse['shortname'], $bulkcourse['summary'], $bulkcourse['format'], $bulkcourse['showgrades'], $bulkcourse['newsitems'], $bulkcourse['teacher'], $bulkcourse['teachers'], $bulkcourse['student'], $bulkcourse['students'], $bulkcourse['startdate'], $bulkcourse['numsections'], $bulkcourse['maxbytes'], $bulkcourse['visible'], $bulkcourse['groupmode'], $bulkcourse['timecreated'], $bulkcourse['timemodified'], $bulkcourse['idnumber'], $bulkcourse['password'], $bulkcourse['enrolperiod'], $bulkcourse['groupmodeforce'], $bulkcourse['metacourse'], $bulkcourse['lang'], $bulkcourse['theme'], $bulkcourse['cost'], $bulkcourse['showreports'], $bulkcourse['guest'], $bulkcourse['enrollable'], $bulkcourse['enrolstartdate'], $bulkcourse['enrolenddate'], $bulkcourse['notifystudents'], $bulkcourse['expirynotify'], $bulkcourse['expirythreshold'], $bulkcourse, $header, $validate, $bulkcourse['topics'], $bulkcourse['teachers_enrol'])) { switch (fastcreatecourse_ex($coursetocategory, $bulkcourse, $header, $validate)) { case 1: $n++; // Succeeded break; case -3: notify('Could not create topic sections for course with ShortName '.$bulkcourse['shortname'],'notifyproblem'); $p++; break; case -4: notify('Could not enrol teachers for course with ShortName '.$bulkcourse['shortname'],'notifyproblem'); $p++; break; case -5: notify('Could not find teacher role for course with ShortName '.$bulkcourse['shortname'],'notifyproblem'); $p++; break; case -6: notify('Could not enrol teacher for course due to course misconfiguration. Course ShortName: '.$bulkcourse['shortname'],'notifyproblem'); $p++; break; default: notify('An Error occured creating course with ShortName '.$bulkcourse['shortname'],'notifyproblem'); break; } } } else { // Skip course, already exists $s++; } $t++; } notify('Created '.$n.' course(s) out of '.$t,'notifysuccess'); if ($s > 0) notify ($s.' course(s) were skipped (duplicate ShortName)','notifysuccess'); if ($p > 0) notify ($p.' course(s) could not be fully created, due to errors. Though they make work, it is advisable to delete them and try again.','notifyproblem'); if (($e = $t - $n - $s - $p) > 0) notify ($e.' course(s) failed due to errors','notifyproblem'); if ($cat_e > 0) notify ($cat_e.' new category(ies) failed due to errors','notifyproblem'); if ($cat_c > 0) { notify ($cat_c.' new category(ies) were created','notifysuccess'); notify ('You may wish to manually Re-Sort the categories','notifysuccess'); // We don't automatically sort alphabetically, as the somewhat clunky category sorting // method used by moodle could annoy the user } fix_course_sortorder(); // Re-sort courses notify('Re-Sorted courses','notifysuccess'); // We potentially did a lot to the Database: avoid tempting fate if (mysql_query('ANALYZE TABLE `'.$CFG->prefix.'course`') && mysql_query('ANALYZE TABLE `'.$CFG->prefix.'course_categories`') && mysql_query('ANALYZE TABLE `'.$CFG->prefix.'course_sections`') && mysql_query('ANALYZE TABLE `'.$CFG->prefix.'user_teachers`')) notify('ANALYZE Database Tables OK','notifysuccess'); else notify('Could not ANALYZE Database Tables (`'.$CFG->prefix.'course`, `'.$CFG->prefix.'course_categories`, `'.$CFG->prefix.'course_sections` and `'.$CFG->prefix.'user_teachers`) - You should do this manually','notifyproblem'); if (mysql_query('OPTIMIZE TABLE `'.$CFG->prefix.'course`') && mysql_query('OPTIMIZE TABLE `'.$CFG->prefix.'course_categories`') && mysql_query('OPTIMIZE TABLE `'.$CFG->prefix.'course_sections`') && mysql_query('OPTIMIZE TABLE `'.$CFG->prefix.'user_teachers`')) notify('OPTIMIZE Database Tables OK','notifysuccess'); else notify('Could not OPTIMIZE Database Tables (`'.$CFG->prefix.'course`, `'.$CFG->prefix.'course_categories`, `'.$CFG->prefix.'course_sections` and `'.$CFG->prefix.'user_teachers`) - You should do this manually','notifyproblem'); $time_end = microtime_float(); notify('Total Execution Time: '.round(($time_end - $time_start),2).' s','notifysuccess'); echo '
'; } else { // Print Help ?>

Upload an RFC4180-Compliant CSV file.
Valid fields for each course are:

FieldValue
category[Forward]Slash-Delimited Category "Path" String (new categories are created as necessary) OR Integer Database Category ID
costString(10)
enrolperiodInteger/Seconds
enrollable0=FALSE,1=TRUE
enrolstartdateString Date Literal
enrolenddateString Date Literal
expirynotify0=FALSE,1=TRUE
expirythresholdInteger Value Between 1-30
formatString('social','topics','weeks')
fullnameString(254)
groupmode0=NOGROUPS,1=SEPARATEGROUPS,2=VISIBLEGROUPS
groupmodeforce0=FALSE,1=TRUE
guest0=NO,1=YES,2=WITHKEY
idnumberString(100)
langString(10)
maxbytesInteger(Site Max)
metacourse0=FALSE,1=TRUE
newsitemsInteger(10)
notifystudents0=FALSE,1=TRUE
numsectionsInteger(52)
passwordString(50)
shortnameString(20)
showgrades0=FALSE,1=TRUE
showreports0=FALSE,1=TRUE
sortorderInteger
startdateString Date Literal
studentString(100)
studentsString(100)
summaryText
teacherString(100)
teachersString(100)
teacher[1,2,...]_accountSearch String that returns only one User Account (as used in Administration » Edit user accounts OR Integer Database User ID
teacher[1,2,...]_roleString(40)
themeString(50)
timecreatedString Date Literal
timemodifiedString Date Literal
topic0 [main heading], topic1 ... topic52 [topic/week headings]Text
visible0=FALSE,1=TRUE
'; echo '
'. $strchoose.':'. ''. ''. ''. '

'; echo ''; print_footer($course); function my_file_get_contents($filename, $use_include_path = 0) { /// Returns the file as one big long string $data = ""; $file = @fopen($filename, "rb", $use_include_path); if ($file) { while (!feof($file)) { $data .= fread($file, 1024); } fclose($file); } return $data; } ?>