/** * Remove all role assignments in the specified course for the specified account * id for the user whose id information is passed in the line data. * * @access public * @static * @param stdClass $course Course in which to remove the role assignment * @param string $ident_field The field (column) name in Moodle user rec against which to query using the imported data * @param stored_file $import_file File in local repository from which to get enrollment and group data * @return string String message with results * * @uses $DB */ public static function unenroll_file(stdClass $course, $ident_field, stored_file $import_file) { global $DB; // Default return value $result = ''; // Need one of these in the loop $course_context = context_course::instance($course->id); // Choose the regex pattern based on the $ident_field switch ($ident_field) { case 'email': $regex_pattern = '/^"?\\s*([a-z0-9][\\w.%-]*@[a-z0-9][a-z0-9.-]{0,61}[a-z0-9]\\.[a-z]{2,6})\\s*"?(?:\\s*[;,\\t]\\s*"?\\s*([a-z0-9][\\w\' .,&-]*))?\\s*"?$/Ui'; break; case 'idnumber': $regex_pattern = '/^"?\\s*(\\d{1,32})\\s*"?(?:\\s*[;,\\t]\\s*"?\\s*([a-z0-9][\\w\' .,&-]*))?\\s*"?$/Ui'; break; default: $regex_pattern = '/^"?\\s*([a-z0-9][\\w@.-]*)\\s*"?(?:\\s*[;,\\t]\\s*"?\\s*([a-z0-9][\\w\' .,&-]*))?\\s*"?$/Ui'; break; } $user_rec = null; // Open and fetch the file contents $fh = $import_file->get_content_file_handle(); $line_num = 0; while (false !== ($line = fgets($fh))) { $line_num++; // Clean these up for each iteration unset($user_rec); if (!($line = trim($line))) { continue; } // Parse the line, from which we may get one or two // matches since the group name is an optional item // on a line by line basis if (!preg_match($regex_pattern, $line, $matches)) { $result .= sprintf(get_string('ERR_PATTERN_MATCH', self::PLUGIN_NAME), $line_num, $line); continue; } $ident_value = $matches[1]; // User must already exist, we import enrollments // into courses, not users into the system. Exclude // records marked as deleted. Because idnumber is // not enforced unique, possible multiple records // returned when using that identifying field, so // use ->get_records method to make that detection // and inform user $user_rec_array = $DB->get_records('user', array($ident_field => addslashes($ident_value), 'deleted' => 0)); // Should have one and only one record, otherwise // report it and move on to the next $user_rec_count = count($user_rec_array); if ($user_rec_count == 0) { // No record found $result .= sprintf(get_string('ERR_USERID_INVALID', self::PLUGIN_NAME), $line_num, $ident_value); continue; } elseif ($user_rec_count > 1) { // Too many records $result .= sprintf(get_string('ERR_USER_MULTIPLE_RECS', self::PLUGIN_NAME), $line_num, $ident_value); continue; } $user_rec = array_shift($user_rec_array); // Fetch all the role assignments this user might have for this course's context. $sql = 'SELECT ue.id, ue.status, ue.enrolid FROM {user_enrolments} ue JOIN {enrol} e ON e.id = ue.enrolid AND e.courseid=:courseid WHERE ue.userid=:userid'; $params = array("courseid" => $course->id, "userid" => $user_rec->id); $user_enrollments = $DB->get_records_sql($sql, $params); if ($user_enrollments) { foreach ($user_enrollments as $ue) { $instance = $DB->get_record('enrol', array('id' => $ue->enrolid), '*', MUST_EXIST); if ($instance->enrol == "meta") { $result .= sprintf(get_string('ERR_UNENROLL_META', self::PLUGIN_NAME), $line_num, $ident_value); } else { try { if (!enrol_is_enabled($instance->enrol)) { print_error('erroreditenrolment', 'enrol'); } $plugin = enrol_get_plugin($instance->enrol); if (!$plugin->allow_unenrol_user($instance, $ue) || !has_capability("enrol/{$instance->enrol}:unenrol", $course_context)) { print_error('erroreditenrolment', 'enrol'); } $plugin->unenrol_user($instance, $user_rec->id); } catch (Exception $exc) { $result .= sprintf(get_string('ERR_UNENROLL_FAILED', self::PLUGIN_NAME), $line_num, $ident_value); $result .= $exc->getMessage(); continue; } } } } } // while fgets fclose($fh); return empty($result) ? get_string('INF_UNENROLL_SUCCESS', self::PLUGIN_NAME) : $result; }
static function ensure_pdf_compatible(stored_file $file) { global $CFG; $fp = $file->get_content_file_handle(); $ident = fread($fp, 10); if (substr_compare('%PDF-', $ident, 0, 5) !== 0) { return false; // This is not a PDF file at all } $ident = substr($ident, 5); // Remove the '%PDF-' part $ident = explode('\\x0A', $ident); // Truncate to first '0a' character list($major, $minor) = explode('.', $ident[0]); // Split the major / minor version $major = intval($major); $minor = intval($minor); if ($major == 0 || $minor == 0) { return false; // Not a valid PDF version number } if ($major = 1 && $minor <= 4) { return true; // We can handle this version - nothing else to do } $temparea = $CFG->dataroot . '/temp/uploadpdf'; $hash = $file->get_contenthash(); $tempsrc = $temparea . "/src-{$hash}.pdf"; $tempdst = $temparea . "/dst-{$hash}.pdf"; if (!file_exists($temparea)) { if (!mkdir($temparea, 0777, true)) { die("Unable to create temporary folder {$temparea}"); } } $file->copy_content_to($tempsrc); // Copy the file $gsexec = $CFG->gs_path; $command = "{$gsexec} -q -sDEVICE=pdfwrite -dBATCH -dNOPAUSE -sOutputFile=\"{$tempdst}\" \"{$tempsrc}\" 2>&1"; $result = exec($command); if (!file_exists($tempdst)) { return false; // Something has gone wrong in the conversion } $file->delete(); // Delete the original file $fs = get_file_storage(); $fileinfo = array('contextid' => $file->get_contextid(), 'component' => $file->get_component(), 'filearea' => $file->get_filearea(), 'itemid' => $file->get_itemid(), 'filename' => $file->get_filename(), 'filepath' => $file->get_filepath()); $fs->create_file_from_pathname($fileinfo, $tempdst); // Create replacement file @unlink($tempsrc); // Delete the temporary files @unlink($tempdst); return true; }
/** * Check to see if PDF is version 1.4 (or below); if not: use ghostscript to convert it * @param stored_file $file * @return string path to copy or converted pdf (false == fail) */ public static function ensure_pdf_compatible(\stored_file $file) { global $CFG; $fp = $file->get_content_file_handle(); $ident = fread($fp, 10); if (substr_compare('%PDF-', $ident, 0, 5) !== 0) { return false; // This is not a PDF file at all. } $ident = substr($ident, 5); // Remove the '%PDF-' part. $ident = explode('\\x0A', $ident); // Truncate to first '0a' character. list($major, $minor) = explode('.', $ident[0]); // Split the major / minor version. $major = intval($major); $minor = intval($minor); if ($major == 0 || $minor == 0) { return false; // Not a valid PDF version number. } $temparea = \make_temp_directory('assignfeedback_editpdf'); $hash = $file->get_contenthash(); // Use the contenthash to make sure the temp files have unique names. $tempsrc = $temparea . "/src-{$hash}.pdf"; $tempdst = $temparea . "/dst-{$hash}.pdf"; if ($major = 1 && $minor <= 4) { // PDF is valid version - just create a copy we can use. $file->copy_content_to($tempdst); // Copy the file. return $tempdst; } $file->copy_content_to($tempsrc); // Copy the file. $gsexec = \get_config('assignfeedback_editpdf', 'gspath'); $command = "{$gsexec} -q -sDEVICE=pdfwrite -dBATCH -dNOPAUSE -sOutputFile=\"{$tempdst}\" \"{$tempsrc}\""; //$command = escapeshellcmd($command); exec($command); @unlink($tempsrc); if (!file_exists($tempdst)) { // Something has gone wrong in the conversion. return false; } return $tempdst; }
/** * Handles the sending of file data to the user's browser, including support for * byteranges etc. * * @category files * @global stdClass $CFG * @global stdClass $COURSE * @global moodle_session $SESSION * @param stored_file $stored_file local file object * @param int $lifetime Number of seconds before the file should expire from caches (default 24 hours) * @param int $filter 0 (default)=no filtering, 1=all files, 2=html files only * @param bool $forcedownload If true (default false), forces download of file rather than view in browser/plugin * @param string $filename Override filename * @param bool $dontdie - return control to caller afterwards. this is not recommended and only used for cleanup tasks. * if this is passed as true, ignore_user_abort is called. if you don't want your processing to continue on cancel, * you must detect this case when control is returned using connection_aborted. Please not that session is closed * and should not be reopened. * @return null script execution stopped unless $dontdie is true */ function send_stored_file($stored_file, $lifetime = 86400, $filter = 0, $forcedownload = false, $filename = null, $dontdie = false) { global $CFG, $COURSE, $SESSION; if (!$stored_file or $stored_file->is_directory()) { // nothing to serve if ($dontdie) { return; } die; } if ($dontdie) { ignore_user_abort(true); } session_get_instance()->write_close(); // unlock session during fileserving // Use given MIME type if specified, otherwise guess it using mimeinfo. // IE, Konqueror and Opera open html file directly in browser from web even when directed to save it to disk :-O // only Firefox saves all files locally before opening when content-disposition: attachment stated $filename = is_null($filename) ? $stored_file->get_filename() : $filename; $isFF = check_browser_version('Firefox', '1.5'); // only FF > 1.5 properly tested $mimetype = ($forcedownload and !$isFF) ? 'application/x-forcedownload' : ($stored_file->get_mimetype() ? $stored_file->get_mimetype() : mimeinfo('type', $filename)); $lastmodified = $stored_file->get_timemodified(); $filesize = $stored_file->get_filesize(); if ($lifetime > 0 && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { // get unixtime of request header; clip extra junk off first $since = strtotime(preg_replace('/;.*$/', '', $_SERVER["HTTP_IF_MODIFIED_SINCE"])); if ($since && $since >= $lastmodified) { header('HTTP/1.1 304 Not Modified'); header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $lifetime) . ' GMT'); header('Cache-Control: max-age=' . $lifetime); header('Content-Type: ' . $mimetype); if ($dontdie) { return; } die; } } //do not put '@' before the next header to detect incorrect moodle configurations, //error should be better than "weird" empty lines for admins/users header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastmodified) . ' GMT'); // if user is using IE, urlencode the filename so that multibyte file name will show up correctly on popup if (check_browser_version('MSIE')) { $filename = rawurlencode($filename); } if ($forcedownload) { header('Content-Disposition: attachment; filename="' . $filename . '"'); } else { header('Content-Disposition: inline; filename="' . $filename . '"'); } if ($lifetime > 0) { header('Cache-Control: max-age=' . $lifetime); header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $lifetime) . ' GMT'); header('Pragma: '); if (empty($CFG->disablebyteserving) && $mimetype != 'text/plain' && $mimetype != 'text/html') { header('Accept-Ranges: bytes'); if (!empty($_SERVER['HTTP_RANGE']) && strpos($_SERVER['HTTP_RANGE'], 'bytes=') !== FALSE) { // byteserving stuff - for acrobat reader and download accelerators // see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35 // inspired by: http://www.coneural.org/florian/papers/04_byteserving.php $ranges = false; if (preg_match_all('/(\\d*)-(\\d*)/', $_SERVER['HTTP_RANGE'], $ranges, PREG_SET_ORDER)) { foreach ($ranges as $key => $value) { if ($ranges[$key][1] == '') { //suffix case $ranges[$key][1] = $filesize - $ranges[$key][2]; $ranges[$key][2] = $filesize - 1; } else { if ($ranges[$key][2] == '' || $ranges[$key][2] > $filesize - 1) { //fix range length $ranges[$key][2] = $filesize - 1; } } if ($ranges[$key][2] != '' && $ranges[$key][2] < $ranges[$key][1]) { //invalid byte-range ==> ignore header $ranges = false; break; } //prepare multipart header $ranges[$key][0] = "\r\n--" . BYTESERVING_BOUNDARY . "\r\nContent-Type: {$mimetype}\r\n"; $ranges[$key][0] .= "Content-Range: bytes {$ranges[$key][1]}-{$ranges[$key][2]}/{$filesize}\r\n\r\n"; } } else { $ranges = false; } if ($ranges) { byteserving_send_file($stored_file->get_content_file_handle(), $mimetype, $ranges, $filesize); } } } else { /// Do not byteserve (disabled, strings, text and html files). header('Accept-Ranges: none'); } } else { // Do not cache files in proxies and browsers 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('Accept-Ranges: none'); // Do not allow byteserving when caching disabled } if (empty($filter)) { if ($mimetype == 'text/plain') { header('Content-Type: Text/plain; charset=utf-8'); //add encoding } else { header('Content-Type: ' . $mimetype); } header('Content-Length: ' . $filesize); //flush the buffers - save memory and disable sid rewrite //this also disables zlib compression prepare_file_content_sending(); // send the contents $stored_file->readfile(); } else { // Try to put the file through filters if ($mimetype == 'text/html') { $options = new stdClass(); $options->noclean = true; $options->nocache = true; // temporary workaround for MDL-5136 $text = $stored_file->get_content(); $text = file_modify_html_header($text); $output = format_text($text, FORMAT_HTML, $options, $COURSE->id); header('Content-Length: ' . strlen($output)); header('Content-Type: text/html'); //flush the buffers - save memory and disable sid rewrite //this also disables zlib compression prepare_file_content_sending(); // send the contents echo $output; } else { if ($mimetype == 'text/plain' and $filter == 1) { // only filter text if filter all files is selected $options = new stdClass(); $options->newlines = false; $options->noclean = true; $text = $stored_file->get_content(); $output = '<pre>' . format_text($text, FORMAT_MOODLE, $options, $COURSE->id) . '</pre>'; header('Content-Length: ' . strlen($output)); header('Content-Type: text/html; charset=utf-8'); //add encoding //flush the buffers - save memory and disable sid rewrite //this also disables zlib compression prepare_file_content_sending(); // send the contents echo $output; } else { // Just send it out raw header('Content-Length: ' . $filesize); header('Content-Type: ' . $mimetype); //flush the buffers - save memory and disable sid rewrite //this also disables zlib compression prepare_file_content_sending(); // send the contents $stored_file->readfile(); } } } if ($dontdie) { return; } die; //no more chars to output!!! }