public function icon($icon) { global $OUTPUT; if (core_useragent::supports_svg()) { switch ($icon) { case 'retweet': return '<svg class="retweeticon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 75 72"><title>' . get_string('retweet', 'block_twitter') . '</title><path d="M70.676 36.644C70.166 35.636 69.13 35 68 35h-7V19c0-2.21-1.79-4-4-4H34c-2.21 0-4 1.79-4 4s1.79 4 4 4h18c.552 0 .998.446 1 .998V35h-7c-1.13 0-2.165.636-2.676 1.644-.51 1.01-.412 2.22.257 3.13l11 15C55.148 55.545 56.046 56 57 56s1.855-.455 2.42-1.226l11-15c.668-.912.767-2.122.256-3.13zM40 48H22c-.54 0-.97-.427-.992-.96L21 36h7c1.13 0 2.166-.636 2.677-1.644.51-1.01.412-2.22-.257-3.13l-11-15C18.854 15.455 17.956 15 17 15s-1.854.455-2.42 1.226l-11 15c-.667.912-.767 2.122-.255 3.13C3.835 35.365 4.87 36 6 36h7l.012 16.003c.002 2.208 1.792 3.997 4 3.997h22.99c2.208 0 4-1.79 4-4s-1.792-4-4-4z"/></svg>'; break; case 'reply': return '<svg class="replyicon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 65 72"><title>' . get_string('reply', 'block_twitter') . '</title><path d="M41 31h-9V19c0-1.14-.647-2.183-1.668-2.688-1.022-.507-2.243-.39-3.15.302l-21 16C5.438 33.18 5 34.064 5 35s.437 1.82 1.182 2.387l21 16c.533.405 1.174.613 1.82.613.453 0 .908-.103 1.33-.312C31.354 53.183 32 52.14 32 51V39h9c5.514 0 10 4.486 10 10 0 2.21 1.79 4 4 4s4-1.79 4-4c0-9.925-8.075-18-18-18z"/></svg>'; break; case 'like': return '<svg class="likeicon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 72"><title>' . get_string('like', 'block_twitter') . '</title><path d="M38.723,12c-7.187,0-11.16,7.306-11.723,8.131C26.437,19.306,22.504,12,15.277,12C8.791,12,3.533,18.163,3.533,24.647 C3.533,39.964,21.891,55.907,27,56c5.109-0.093,23.467-16.036,23.467-31.353C50.467,18.163,45.209,12,38.723,12z"/></svg>'; break; default: return ''; break; } } else { switch ($icon) { case 'retweet': return $OUTPUT->pix_icon('retweet', get_string('retweet', 'block_twitter'), 'block_twitter', array('class' => 'icon default')) . $OUTPUT->pix_icon('retweet_hover', get_string('retweet', 'block_twitter'), 'block_twitter', array('class' => 'icon hover')); break; case 'reply': return $OUTPUT->pix_icon('reply', get_string('reply', 'block_twitter'), 'block_twitter', array('class' => 'icon default')) . $OUTPUT->pix_icon('reply_hover', get_string('reply', 'block_twitter'), 'block_twitter', array('class' => 'icon hover')); break; case 'like': return $OUTPUT->pix_icon('like', get_string('like', 'block_twitter'), 'block_twitter', array('class' => 'icon default')) . $OUTPUT->pix_icon('like_hover', get_string('like', 'block_twitter'), 'block_twitter', array('class' => 'icon hover')); break; default: return ''; break; } } }
protected function is_legacy_browser() { // IE8 and IE9 are the only supported browsers that do not have spellchecker. if (core_useragent::is_ie() and !core_useragent::check_ie_version(10)) { return true; } // The rest of browsers supports spellchecking or is horribly outdated and we do not care... return false; }
public function get_content() { global $CFG; if ($this->content !== null) { return $this->content; } $this->content = new stdClass(); $obj = new login_msg_lib(); $baseurl = $obj->get_base(); $welcomepage = $obj->get_welcome(); $jquerycdn = 'https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js'; $databaseobj = core_useragent::instance(); $device = $databaseobj->get_device_type(); $jquery = <<<JQ <script type="text/javascript" src="{$jquerycdn}"></script> JQ; if ($device == 'mobile' || $device == 'tablet') { $jquery = ''; } if (empty($welcomepage)) { $popupjs = <<<HTML {$jquery} HTML; } else { $popupjs = <<<HTML {$jquery} <!--ThickBox 3--> <script> // Add popup fade? function welcome() { var win_width = 600; var win_height = 400; var left = screen.width / 2 - win_width/2; var top = screen.height /2 - win_height/2; var winoptions = "width="+win_width+", height="+win_height+", top="+top+", left="+left; var popup = window.open("{$welcomepage}", "Welcome", winoptions ); } setTimeout( function(){welcome();}, 3000); </script> HTML; } $this->content->text = <<<HTML {$popupjs} <script type="text/javascript" src="{$baseurl}js/thickbox/thickbox.js"></script> <link rel="stylesheet" href="{$baseurl}js/thickbox/thickbox.css" type="text/css" media="screen" /> <!-- /ThickBox 3 --> <div id="log_meg_small"> <!-- link to reopen message --!> <p> <a href="{$welcomepage}" target="_blank">Welcome</a> </p> <p> <a href="https://www.youtube.com/watch?v=GDk1YOP2f4A" \ttarget="_blank">Why Durabuilt?</a> </p> </div> HTML; $this->content->footer = ''; return $this->content; }
/** * Pre-test setup. Preserves $CFG. */ public function setUp() { parent::setUp(); // Reset $CFG and $SERVER. $this->resetAfterTest(); // Consistent initial setup: all players disabled. \core\plugininfo\media::set_enabled_plugins('videojs'); // Pretend to be using Firefox browser (must support ogg for tests to work). core_useragent::instance(true, 'Mozilla/5.0 (X11; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0 '); }
/** * Returns general link or file embedding html. * @param string $fullurl * @param string $title * @param string $clicktoopen * @return string html */ function tab_embed_general($fullurl, $title, $clicktoopen, $mimetype) { global $CFG, $PAGE; $iframe = false; $forcelink = false; // IE can not embed stuff properly if stored on different server. // That is why we use iframe instead, unfortunately this tag does not validate. // In xhtml strict mode. if ($mimetype === 'text/html' and core_useragent::check_browser_version('MSIE', 5)) { debugging("Detected IE", DEBUG_DEVELOPER); if (preg_match('(^https?://[^/]*)', $fullurl, $matches)) { debugging("Detected IE w/ http://", DEBUG_DEVELOPER); // Make sure we aren't redirecting to a moodle page. if (strpos($CFG->wwwroot, $matches[0]) !== 0) { $forcelink = true; } else { // If it is a moodle then embed as iframe. $iframe = true; } } } $idsuffix = md5($fullurl); // We force the link because IE doesn't support embedding web pages. if ($forcelink) { $clicktoopen = get_string('embed_fail_msg_ie', 'tab') . "<a href='{$fullurl}' target='_blank'>" . get_string('embed_fail_link_text', 'tab') . '</a>'; $code = <<<EOT <div class="resourcecontent resourcegeneral"> {$clicktoopen} </div> EOT; } else { if ($iframe) { $code = <<<EOT <div class="resourcecontent resourcegeneral"> <iframe id="resourceobject_{$idsuffix}" src="{$fullurl}"> {$clicktoopen} </iframe> </div> EOT; } else { $code = <<<EOT <div class="resourcecontent resourcegeneral"> <object id="resourceobject_{$idsuffix}" data="{$fullurl}" type="{$mimetype}"> <param name="src" value="{$fullurl}" /> {$clicktoopen} </object> </div> EOT; } } $PAGE->requires->js_init_call('M.mod_tab.init_maximised_embed', array("resourceobject_{$idsuffix}"), true); return $code; }
protected function can_use_drag_and_drop() { global $USER; $ie = core_useragent::check_browser_version('MSIE', 6.0); $ff = core_useragent::check_browser_version('Gecko', 20051106); $op = core_useragent::check_browser_version('Opera', 9.0); $sa = core_useragent::check_browser_version('Safari', 412); $ch = core_useragent::check_browser_version('Chrome', 6); if (!$ie && !$ff && !$op && !$sa && !$ch or !empty($USER->screenreader)) { return false; } return true; }
public function list_supported_urls(array $urls, array $options = array()) { $extensions = $this->get_supported_extensions(); $result = array(); foreach ($urls as $url) { $ext = core_media_manager::instance()->get_extension($url); if (in_array('.' . $ext, $extensions) && core_useragent::supports_html5($ext)) { // Unfortunately html5 video does not handle fallback properly. // https://www.w3.org/Bugs/Public/show_bug.cgi?id=10975 // That means we need to do browser detect and not use html5 on // browsers which do not support the given type, otherwise users // will not even see the fallback link. $result[] = $url; } } return $result; }
/** * Returns whether ajax is enabled/allowed or not. * @param array $browsers optional list of alowed browsers, empty means use default list * @return bool */ function ajaxenabled(array $browsers = null) { global $CFG; if (!empty($browsers)) { $valid = false; foreach ($browsers as $brand => $version) { if (core_useragent::check_browser_version($brand, $version)) { $valid = true; } } if (!$valid) { return false; } } if (!empty($CFG->enableajax)) { return true; } else { return false; } }
/** * This function will test directives used to serve SVG images to make sure * this are making the right decisions. */ public function test_svg_image_use() { global $CFG; $this->resetAfterTest(); // The two required tests. $this->assertTrue(file_exists($CFG->dirroot . '/pix/i/test.svg')); $this->assertTrue(file_exists($CFG->dirroot . '/pix/i/test.png')); $theme = theme_config::load(theme_config::DEFAULT_THEME); // First up test the forced setting. $imagefile = $theme->resolve_image_location('i/test', 'moodle', true); $this->assertSame('test.svg', basename($imagefile)); $imagefile = $theme->resolve_image_location('i/test', 'moodle', false); $this->assertSame('test.png', basename($imagefile)); // Now test the use of the svgicons config setting. // We need to clone the theme as usesvg property is calculated only once. $testtheme = clone $theme; $CFG->svgicons = true; $imagefile = $testtheme->resolve_image_location('i/test', 'moodle', null); $this->assertSame('test.svg', basename($imagefile)); $CFG->svgicons = false; // We need to clone the theme as usesvg property is calculated only once. $testtheme = clone $theme; $imagefile = $testtheme->resolve_image_location('i/test', 'moodle', null); $this->assertSame('test.png', basename($imagefile)); unset($CFG->svgicons); // Finally test a few user agents. $useragents = array('Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)' => false, 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)' => false, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/4.0)' => false, 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)' => false, 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)' => true, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/5.0)' => false, 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0; Touch)' => true, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; Trident/6.0; Touch; .NET4.0E; .NET4.0C; Tablet PC 2.0)' => true, 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0)' => true, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.3; Trident/7.0; .NET4.0E; .NET4.0C)' => true, 'Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/11.0.652.0 Safari/534.17' => true, 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1' => true, 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1' => true, 'Mozilla/5.0 (Windows NT 6.1; rv:1.9) Gecko/20100101 Firefox/4.0' => true, 'Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120716 Firefox/15.0.1' => true, 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1' => true, 'Opera/9.80 (X11; Linux x86_64; U; en) Presto/2.10.289 Version/12.02' => false, 'Mozilla/5.0 (Linux; U; Android 0.5; en-us) AppleWebKit/522+ (KHTML, like Gecko) Safari/419.3' => false, 'Mozilla/5.0 (Linux; U; Android 2.3.5; en-us; HTC Vision Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => false, 'Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => true, 'Mozilla/5.0 (Linux; Android 4.3; it-it; SAMSUNG GT-I9505/I9505XXUEMJ7 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.5 Chrome/28.0.1500.94 Mobile Safari/537.36' => true); foreach ($useragents as $agent => $expected) { core_useragent::instance(true, $agent); // We need to clone the theme as usesvg property is calculated only once. $testtheme = clone $theme; $imagefile = $testtheme->resolve_image_location('i/test', 'moodle', null); if ($expected) { $this->assertSame('test.svg', basename($imagefile), 'Incorrect image returned for user agent `' . $agent . '`'); } else { $this->assertSame('test.png', basename($imagefile), 'Incorrect image returned for user agent `' . $agent . '`'); } } }
/** * Redirects the user to another page, after printing a notice. * * This function calls the OUTPUT redirect method, echo's the output and then dies to ensure nothing else happens. * * <strong>Good practice:</strong> You should call this method before starting page * output by using any of the OUTPUT methods. * * @param moodle_url|string $url A moodle_url to redirect to. Strings are not to be trusted! * @param string $message The message to display to the user * @param int $delay The delay before redirecting * @throws moodle_exception */ function redirect($url, $message = '', $delay = -1) { global $OUTPUT, $PAGE, $CFG; if (CLI_SCRIPT or AJAX_SCRIPT) { // This is wrong - developers should not use redirect in these scripts but it should not be very likely. throw new moodle_exception('redirecterrordetected', 'error'); } // Prevent debug errors - make sure context is properly initialised. if ($PAGE) { $PAGE->set_context(null); $PAGE->set_pagelayout('redirect'); // No header and footer needed. $PAGE->set_title(get_string('pageshouldredirect', 'moodle')); } if ($url instanceof moodle_url) { $url = $url->out(false); } $debugdisableredirect = false; do { if (defined('DEBUGGING_PRINTED')) { // Some debugging already printed, no need to look more. $debugdisableredirect = true; break; } if (core_useragent::is_msword()) { // Clicking a URL from MS Word sends a request to the server without cookies. If that // causes a redirect Word will open a browser pointing the new URL. If not, the URL that // was clicked is opened. Because the request from Word is without cookies, it almost // always results in a redirect to the login page, even if the user is logged in in their // browser. This is not what we want, so prevent the redirect for requests from Word. $debugdisableredirect = true; break; } if (empty($CFG->debugdisplay) or empty($CFG->debug)) { // No errors should be displayed. break; } if (!function_exists('error_get_last') or !($lasterror = error_get_last())) { break; } if (!($lasterror['type'] & $CFG->debug)) { // Last error not interesting. break; } // Watch out here, @hidden() errors are returned from error_get_last() too. if (headers_sent()) { // We already started printing something - that means errors likely printed. $debugdisableredirect = true; break; } if (ob_get_level() and ob_get_contents()) { // There is something waiting to be printed, hopefully it is the errors, // but it might be some error hidden by @ too - such as the timezone mess from setup.php. $debugdisableredirect = true; break; } } while (false); // Technically, HTTP/1.1 requires Location: header to contain the absolute path. // (In practice browsers accept relative paths - but still, might as well do it properly.) // This code turns relative into absolute. if (!preg_match('|^[a-z]+:|', $url)) { // Get host name http://www.wherever.com. $hostpart = preg_replace('|^(.*?[^:/])/.*$|', '$1', $CFG->wwwroot); if (preg_match('|^/|', $url)) { // URLs beginning with / are relative to web server root so we just add them in. $url = $hostpart . $url; } else { // URLs not beginning with / are relative to path of current script, so add that on. $url = $hostpart . preg_replace('|\\?.*$|', '', me()) . '/../' . $url; } // Replace all ..s. while (true) { $newurl = preg_replace('|/(?!\\.\\.)[^/]*/\\.\\./|', '/', $url); if ($newurl == $url) { break; } $url = $newurl; } } // Sanitise url - we can not rely on moodle_url or our URL cleaning // because they do not support all valid external URLs. $url = preg_replace('/[\\x00-\\x1F\\x7F]/', '', $url); $url = str_replace('"', '%22', $url); $encodedurl = preg_replace("/\\&(?![a-zA-Z0-9#]{1,8};)/", "&", $url); $encodedurl = preg_replace('/^.*href="([^"]*)".*$/', "\\1", clean_text('<a href="' . $encodedurl . '" />', FORMAT_HTML)); $url = str_replace('&', '&', $encodedurl); if (!empty($message)) { if ($delay === -1 || !is_numeric($delay)) { $delay = 3; } $message = clean_text($message); } else { $message = get_string('pageshouldredirect'); $delay = 0; } // Make sure the session is closed properly, this prevents problems in IIS // and also some potential PHP shutdown issues. \core\session\manager::write_close(); if ($delay == 0 && !$debugdisableredirect && !headers_sent()) { // 302 might not work for POST requests, 303 is ignored by obsolete clients. @header($_SERVER['SERVER_PROTOCOL'] . ' 303 See Other'); @header('Location: ' . $url); echo bootstrap_renderer::plain_redirect_message($encodedurl); exit; } // Include a redirect message, even with a HTTP redirect, because that is recommended practice. if ($PAGE) { $CFG->docroot = false; // To prevent the link to moodle docs from being displayed on redirect page. echo $OUTPUT->redirect_message($encodedurl, $message, $delay, $debugdisableredirect); exit; } else { echo bootstrap_renderer::early_redirect_message($encodedurl, $message, $delay); exit; } }
/** * Handles the sending of file data to the user's browser, including support for * byteranges etc. * * The $options parameter supports the following keys: * (string|null) preview - send the preview of the file (e.g. "thumb" for a thumbnail) * (string|null) filename - overrides the implicit filename * (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. * * @category files * @param stored_file $stored_file local file object * @param int $lifetime Number of seconds before the file should expire from caches (null means $CFG->filelifetime) * @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 array $options additional options affecting the file serving * @return null script execution stopped unless $options['dontdie'] is true */ function send_stored_file($stored_file, $lifetime = null, $filter = 0, $forcedownload = false, array $options = array()) { global $CFG, $COURSE; if (empty($options['filename'])) { $filename = null; } else { $filename = $options['filename']; } if (empty($options['dontdie'])) { $dontdie = false; } else { $dontdie = true; } if ($lifetime === 'default' or is_null($lifetime)) { $lifetime = $CFG->filelifetime; } if (!empty($options['preview'])) { // replace the file with its preview $fs = get_file_storage(); $preview_file = $fs->get_file_preview($stored_file, $options['preview']); if (!$preview_file) { // unable to create a preview of the file, send its default mime icon instead if ($options['preview'] === 'tinyicon') { $size = 24; } else { if ($options['preview'] === 'thumb') { $size = 90; } else { $size = 256; } } $fileicon = file_file_icon($stored_file, $size); send_file($CFG->dirroot . '/pix/' . $fileicon . '.png', basename($fileicon) . '.png'); } else { // preview images have fixed cache lifetime and they ignore forced download // (they are generated by GD and therefore they are considered reasonably safe). $stored_file = $preview_file; $lifetime = DAYSECS; $filter = 0; $forcedownload = false; } } // handle external resource if ($stored_file && $stored_file->is_external_file() && !isset($options['sendcachedexternalfile'])) { $stored_file->send_file($lifetime, $filter, $forcedownload, $options); die; } if (!$stored_file or $stored_file->is_directory()) { // nothing to serve if ($dontdie) { return; } die; } if ($dontdie) { ignore_user_abort(true); } \core\session\manager::write_close(); // Unlock session during file serving. // 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 = core_useragent::is_firefox(); // only FF properly tested $mimetype = ($forcedownload and !$isFF) ? 'application/x-forcedownload' : ($stored_file->get_mimetype() ? $stored_file->get_mimetype() : mimeinfo('type', $filename)); // if user is using IE, urlencode the filename so that multibyte file name will show up correctly on popup if (core_useragent::is_ie()) { $filename = rawurlencode($filename); } if ($forcedownload) { header('Content-Disposition: attachment; filename="' . $filename . '"'); } else { header('Content-Disposition: inline; filename="' . $filename . '"'); } if ($lifetime > 0) { $private = ''; if (isloggedin() and !isguestuser()) { $private = ' private,'; } header('Cache-Control:' . $private . ' max-age=' . $lifetime . ', no-transform'); header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $lifetime) . ' GMT'); header('Pragma: '); } 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: private, max-age=10, no-transform'); 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, no-transform'); header('Expires: ' . gmdate('D, d M Y H:i:s', 0) . ' GMT'); header('Pragma: no-cache'); } } if (empty($filter)) { // send the contents readfile_accel($stored_file, $mimetype, !$dontdie); } 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); readstring_accel($output, $mimetype, false); } 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>'; readstring_accel($output, $mimetype, false); } else { // Just send it out raw readfile_accel($stored_file, $mimetype, !$dontdie); } } } if ($dontdie) { return; } die; //no more chars to output!!! }
/** * Will get called before the login page is shownr. Ff NTLM SSO * is enabled, and the user is in the right network, we'll redirect * to the magic NTLM page for SSO... * */ function loginpage_hook() { global $CFG, $SESSION; // HTTPS is potentially required //httpsrequired(); - this must be used before setting the URL, it is already done on the login/index.php if (($_SERVER['REQUEST_METHOD'] === 'GET' || $_SERVER['REQUEST_METHOD'] === 'POST' && get_local_referer() != strip_querystring(qualified_me())) && !empty($this->config->ntlmsso_enabled) && !empty($this->config->ntlmsso_subnet) && empty($_GET['authldap_skipntlmsso']) && (isguestuser() || !isloggedin()) && address_in_subnet(getremoteaddr(), $this->config->ntlmsso_subnet)) { // First, let's remember where we were trying to get to before we got here if (empty($SESSION->wantsurl)) { $SESSION->wantsurl = null; $referer = get_local_referer(false); if ($referer && $referer != $CFG->wwwroot && $referer != $CFG->wwwroot . '/' && $referer != $CFG->httpswwwroot . '/login/' && $referer != $CFG->httpswwwroot . '/login/index.php') { $SESSION->wantsurl = $referer; } } // Now start the whole NTLM machinery. if ($this->config->ntlmsso_ie_fastpath == AUTH_NTLM_FASTPATH_YESATTEMPT || $this->config->ntlmsso_ie_fastpath == AUTH_NTLM_FASTPATH_YESFORM) { if (core_useragent::is_ie()) { $sesskey = sesskey(); redirect($CFG->wwwroot . '/auth/ldap/ntlmsso_magic.php?sesskey=' . $sesskey); } else { if ($this->config->ntlmsso_ie_fastpath == AUTH_NTLM_FASTPATH_YESFORM) { redirect($CFG->httpswwwroot . '/login/index.php?authldap_skipntlmsso=1'); } } } redirect($CFG->wwwroot . '/auth/ldap/ntlmsso_attempt.php'); } // No NTLM SSO, Use the normal login page instead. // If $SESSION->wantsurl is empty and we have a 'Referer:' header, the login // page insists on redirecting us to that page after user validation. If // we clicked on the redirect link at the ntlmsso_finish.php page (instead // of waiting for the redirection to happen) then we have a 'Referer:' header // we don't want to use at all. As we can't get rid of it, just point // $SESSION->wantsurl to $CFG->wwwroot (after all, we came from there). if (empty($SESSION->wantsurl) && get_local_referer() == $CFG->httpswwwroot . '/auth/ldap/ntlmsso_finish.php') { $SESSION->wantsurl = $CFG->wwwroot; } }
/** * Checks if current user is a web crawler. * * This list can not be made complete, this is not a security * restriction, we make the list only to help these sites * especially when automatic guest login is disabled. * * If admin needs security they should enable forcelogin * and disable guest access!! * * @return bool * @deprecated since Moodle 3.0 use \core_useragent::is_web_crawler instead. */ function is_web_crawler() { debugging('is_web_crawler() has been deprecated, please use core_useragent::is_web_crawler() instead.', DEBUG_DEVELOPER); return core_useragent::is_web_crawler(); }
<!-- End Analytics --> </head> <body <?php echo $OUTPUT->body_attributes($bodyclasses); ?> > <?php echo $OUTPUT->standard_top_of_body_html(); ?> <?php // If on desktop, then hide the header/footer. $hideclass = ''; $devicetype = core_useragent::get_device_type(); if ($devicetype !== 'mobile' and $devicetype !== 'tablet') { // We can not use the Bootstrap responsive css classes because popups are phone sized on desktop. $hideclass = 'hide'; } ?> <header role="banner" class="navbar navbar-fixed-top moodle-has-zindex <?php echo $hideclass; ?> "> <nav role="navigation" class="navbar-inner"> <div class="container-fluid"> <a class="brand" href="<?php echo $CFG->wwwroot; ?>
} } echo '</select> <input type="submit" value="' . get_string('showsession', 'realtimequiz') . '" /></form></center>'; if ($CFG->version < 2013111800) { $tickimg = '<img src="' . $OUTPUT->pix_url('i/tick_green_big') . '" alt="' . get_string('tick', 'realtimequiz') . '" />'; $crossimg = '<img src="' . $OUTPUT->pix_url('i/cross_red_big') . '" alt="' . get_string('cross', 'realtimequiz') . '" />'; } else { $tickimg = '<img src="' . $OUTPUT->pix_url('i/grade_correct') . '" alt="' . get_string('tick', 'realtimequiz') . '" />'; $crossimg = '<img src="' . $OUTPUT->pix_url('i/grade_incorrect') . '" alt="' . get_string('cross', 'realtimequiz') . '" />'; } if ($questionid == 0) { // Show all of the questions if ($CFG->version < 2013111800) { $isff = check_browser_version('Gecko'); } else { $isff = core_useragent::check_browser_version('Gecko'); } if ($isff) { $blankcolspan = 'colspan="999" '; } else { $blankcolspan = ''; } $questions = $DB->get_records('realtimequiz_question', array('quizid' => $realtimequiz->id), 'questionnum'); $linkurl = new moodle_url('/mod/realtimequiz/responses.php', array('id' => $cm->id, 'showsession' => $showsession)); if ($showusers) { $linkurl->param('showusers', 1); if ($CFG->version < 2013111800) { $usernames = 'u.firstname, u.lastname'; } else { $usernames = get_all_user_name_fields(true, 'u'); }
define('NO_MOODLE_COOKIES', false); } } } } } // Start session and prepare global $SESSION, $USER. if (empty($CFG->sessiontimeout)) { $CFG->sessiontimeout = 7200; } \core\session\manager::start(); // Set default content type and encoding, developers are still required to use // echo $OUTPUT->header() everywhere, anything that gets set later should override these headers. // This is intended to mitigate some security problems. if (AJAX_SCRIPT) { if (!core_useragent::supports_json_contenttype()) { // Some bloody old IE. @header('Content-type: text/plain; charset=utf-8'); @header('X-Content-Type-Options: nosniff'); } else { if (!empty($_FILES)) { // Some ajax code may have problems with json and file uploads. @header('Content-type: text/plain; charset=utf-8'); } else { @header('Content-type: application/json; charset=utf-8'); } } } else { if (!CLI_SCRIPT) { @header('Content-type: text/html; charset=utf-8'); }
/** * Get an instance of the user agent object. * * @param bool $reload If set to true the user agent will be reset and all ascertations remade. * @param string $forceuseragent The string to force as the user agent, don't use unless absolutely unavoidable. * @return core_useragent */ public static function instance($reload = false, $forceuseragent = null) { if (!self::$instance || $reload) { self::$instance = new core_useragent($forceuseragent); } return self::$instance; }
/** * Sets user agent to Firefox. */ private function pretend_to_be_firefox() { // Pretend to be using Firefox browser (must support ogg for tests to work). core_useragent::instance(true, 'Mozilla/5.0 (Windows NT 6.1; rv:8.0) Gecko/20100101 Firefox/8.0'); }
/** * States if the browser is IE by returning properties, otherwise false. */ public function theme_essential_ie_properties() { $properties = core_useragent::check_ie_properties(); // In /lib/classes/useragent.php. if (!is_array($properties)) { return false; } else { return $properties; } }
/** * Close the Moodle Workbook */ public function close() { global $CFG; foreach ($this->objPHPExcel->getAllSheets() as $sheet) { $sheet->setSelectedCells('A1'); } $this->objPHPExcel->setActiveSheetIndex(0); $filename = preg_replace('/\\.xlsx?$/i', '', $this->filename); $mimetype = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; $filename = $filename . '.xlsx'; if (is_https()) { // 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'); } if (core_useragent::is_ie()) { $filename = rawurlencode($filename); } else { $filename = s($filename); } header('Content-Type: ' . $mimetype); header('Content-Disposition: attachment;filename="' . $filename . '"'); $objWriter = PHPExcel_IOFactory::createWriter($this->objPHPExcel, $this->type); $objWriter->save('php://output'); }
/** * Handles the sending of file data to the user's browser, including support for * byteranges etc. * * The $options parameter supports the following keys: * (string|null) preview - send the preview of the file (e.g. "thumb" for a thumbnail) * (string|null) filename - overrides the implicit filename * (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 * (string|null) cacheability - force the cacheability setting of the HTTP response, "private" or "public", * when $lifetime is greater than 0. Cacheability defaults to "private" when logged in as other than guest; otherwise, * defaults to "public". * * @category files * @param stored_file $stored_file local file object * @param int $lifetime Number of seconds before the file should expire from caches (null means $CFG->filelifetime) * @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 array $options additional options affecting the file serving * @return null script execution stopped unless $options['dontdie'] is true */ function send_stored_file($stored_file, $lifetime = null, $filter = 0, $forcedownload = false, array $options = array()) { global $CFG, $COURSE; if (empty($options['filename'])) { $filename = null; } else { $filename = $options['filename']; } if (empty($options['dontdie'])) { $dontdie = false; } else { $dontdie = true; } if ($lifetime === 'default' or is_null($lifetime)) { $lifetime = $CFG->filelifetime; } if (!empty($options['preview'])) { // replace the file with its preview $fs = get_file_storage(); $preview_file = $fs->get_file_preview($stored_file, $options['preview']); if (!$preview_file) { // unable to create a preview of the file, send its default mime icon instead if ($options['preview'] === 'tinyicon') { $size = 24; } else { if ($options['preview'] === 'thumb') { $size = 90; } else { $size = 256; } } $fileicon = file_file_icon($stored_file, $size); send_file($CFG->dirroot . '/pix/' . $fileicon . '.png', basename($fileicon) . '.png'); } else { // preview images have fixed cache lifetime and they ignore forced download // (they are generated by GD and therefore they are considered reasonably safe). $stored_file = $preview_file; $lifetime = DAYSECS; $filter = 0; $forcedownload = false; } } // handle external resource if ($stored_file && $stored_file->is_external_file() && !isset($options['sendcachedexternalfile'])) { $stored_file->send_file($lifetime, $filter, $forcedownload, $options); die; } if (!$stored_file or $stored_file->is_directory()) { // nothing to serve if ($dontdie) { return; } die; } if ($dontdie) { ignore_user_abort(true); } \core\session\manager::write_close(); // Unlock session during file serving. $filename = is_null($filename) ? $stored_file->get_filename() : $filename; // Use given MIME type if specified. $mimetype = $stored_file->get_mimetype(); // Otherwise guess it. if (!$mimetype || $mimetype === 'document/unknown') { $mimetype = get_mimetype_for_sending($filename); } // if user is using IE, urlencode the filename so that multibyte file name will show up correctly on popup if (core_useragent::is_ie()) { $filename = rawurlencode($filename); } if ($forcedownload) { header('Content-Disposition: attachment; filename="' . $filename . '"'); } else { if ($mimetype !== 'application/x-shockwave-flash') { // If this is an swf don't pass content-disposition with filename as this makes the flash player treat the file // as an upload and enforces security that may prevent the file from being loaded. header('Content-Disposition: inline; filename="' . $filename . '"'); } } if ($lifetime > 0) { $cacheability = ' public,'; if (!empty($options['cacheability']) && $options['cacheability'] === 'public') { // This file must be cache-able by both browsers and proxies. $cacheability = ' public,'; } else { if (!empty($options['cacheability']) && $options['cacheability'] === 'private') { // This file must be cache-able only by browsers. $cacheability = ' private,'; } else { if (isloggedin() and !isguestuser()) { $cacheability = ' private,'; } } } header('Cache-Control:' . $cacheability . ' max-age=' . $lifetime . ', no-transform'); header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $lifetime) . ' GMT'); header('Pragma: '); } else { // Do not cache files in proxies and browsers if (is_https()) { // HTTPS sites - watch out for IE! KB812935 and KB316431. header('Cache-Control: private, max-age=10, no-transform'); 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, no-transform'); header('Expires: ' . gmdate('D, d M Y H:i:s', 0) . ' GMT'); header('Pragma: no-cache'); } } // Allow cross-origin requests only for Web Services. // This allow to receive requests done by Web Workers or webapps in different domains. if (WS_SERVER) { header('Access-Control-Allow-Origin: *'); } if (empty($filter)) { // send the contents readfile_accel($stored_file, $mimetype, !$dontdie); } else { // Try to put the file through filters if ($mimetype == 'text/html' || $mimetype == 'application/xhtml+xml') { $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); readstring_accel($output, $mimetype, false); } 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>'; readstring_accel($output, $mimetype, false); } else { // Just send it out raw readfile_accel($stored_file, $mimetype, !$dontdie); } } } if ($dontdie) { return; } die; //no more chars to output!!! }
public function list_supported_urls(array $urls, array $options = array()) { $extensions = $this->get_supported_extensions(); $result = array(); foreach ($urls as $url) { $ext = core_media::get_extension($url); if (in_array($ext, $extensions)) { if ($ext === 'ogg' || $ext === 'oga') { // Formats .ogg and .oga are not supported in IE, Edge, or Safari. if (core_useragent::is_ie() || core_useragent::is_edge() || core_useragent::is_safari()) { continue; } } else { // Formats .aac, .mp3, and .m4a are not supported in Opera. if (core_useragent::is_opera()) { continue; } // Formats .mp3 and .m4a were not reliably supported in Firefox before 27. // https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats // has the details. .aac is still not supported. if (core_useragent::is_firefox() && ($ext === 'aac' || !core_useragent::check_firefox_version(27))) { continue; } } // Old Android versions (pre 2.3.3) 'support' audio tag but no codecs. if (core_useragent::is_webkit_android() && !core_useragent::is_webkit_android('533.1')) { continue; } $result[] = $url; } } return $result; }
/** * Prepares the start of an AJAX output. */ public function header() { // unfortunately YUI iframe upload does not support application/json if (!empty($_FILES)) { @header('Content-type: text/plain; charset=utf-8'); if (!core_useragent::supports_json_contenttype()) { @header('X-Content-Type-Options: nosniff'); } } else if (!core_useragent::supports_json_contenttype()) { @header('Content-type: text/plain; charset=utf-8'); @header('X-Content-Type-Options: nosniff'); } else { @header('Content-type: application/json; charset=utf-8'); } // Headers to make it not cacheable and json @header('Cache-Control: no-store, no-cache, must-revalidate'); @header('Cache-Control: post-check=0, pre-check=0', false); @header('Pragma: no-cache'); @header('Expires: Mon, 20 Aug 1969 09:23:00 GMT'); @header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); @header('Accept-Ranges: none'); }
* Configuration for Moodle's bootstrap theme. * * DO NOT MODIFY THIS THEME! * COPY IT FIRST, THEN RENAME THE COPY AND MODIFY IT INSTEAD. * * For full information about creating Moodle themes, see: * http://docs.moodle.org/dev/Themes_2.0 * * @package theme_bootstrapbase * @copyright 2013 Bas Brands. www.sonsbeekmedia.nl * @author Bas Brands * @author David Scotson * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ $THEME->doctype = 'html5'; $THEME->yuicssmodules = array(); $THEME->name = 'bootstrapbase'; $THEME->parents = array(); $THEME->sheets = array('moodle'); $THEME->supportscssoptimisation = false; $THEME->enable_dock = false; $THEME->editor_sheets = array('editor'); $THEME->rendererfactory = 'theme_overridden_renderer_factory'; $THEME->layouts = array('base' => array('file' => 'columns1.php', 'regions' => array()), 'standard' => array('file' => 'columns3.php', 'regions' => array('side-pre', 'side-post'), 'defaultregion' => 'side-pre'), 'course' => array('file' => 'columns3.php', 'regions' => array('side-pre', 'side-post'), 'defaultregion' => 'side-pre', 'options' => array('langmenu' => true)), 'coursecategory' => array('file' => 'columns3.php', 'regions' => array('side-pre', 'side-post'), 'defaultregion' => 'side-pre'), 'incourse' => array('file' => 'columns3.php', 'regions' => array('side-pre', 'side-post'), 'defaultregion' => 'side-pre'), 'frontpage' => array('file' => 'columns3.php', 'regions' => array('side-pre', 'side-post'), 'defaultregion' => 'side-pre', 'options' => array('nonavbar' => true)), 'admin' => array('file' => 'columns2.php', 'regions' => array('side-pre'), 'defaultregion' => 'side-pre'), 'mydashboard' => array('file' => 'columns3.php', 'regions' => array('side-pre', 'side-post'), 'defaultregion' => 'side-pre', 'options' => array('langmenu' => true)), 'mypublic' => array('file' => 'columns3.php', 'regions' => array('side-pre', 'side-post'), 'defaultregion' => 'side-pre'), 'login' => array('file' => 'columns1.php', 'regions' => array(), 'options' => array('langmenu' => true)), 'popup' => array('file' => 'popup.php', 'regions' => array(), 'options' => array('nofooter' => true, 'nonavbar' => true)), 'frametop' => array('file' => 'columns1.php', 'regions' => array(), 'options' => array('nofooter' => true, 'nocoursefooter' => true)), 'embedded' => array('file' => 'embedded.php', 'regions' => array()), 'maintenance' => array('file' => 'maintenance.php', 'regions' => array()), 'print' => array('file' => 'columns1.php', 'regions' => array(), 'options' => array('nofooter' => true, 'nonavbar' => false)), 'redirect' => array('file' => 'embedded.php', 'regions' => array()), 'report' => array('file' => 'columns2.php', 'regions' => array('side-pre'), 'defaultregion' => 'side-pre'), 'secure' => array('file' => 'secure.php', 'regions' => array('side-pre', 'side-post'), 'defaultregion' => 'side-pre')); $THEME->javascripts = array(); $THEME->javascripts_footer = array('moodlebootstrap', 'dock'); if (core_useragent::is_ie() && !core_useragent::check_ie_version('9.0')) { $THEME->javascripts[] = 'html5shiv'; } $THEME->hidefromselector = true; $THEME->blockrtlmanipulations = array('side-pre' => 'side-post', 'side-post' => 'side-pre');
/** * Initialises the CSS classes that will be added to body tag of the page. * * The function is responsible for adding all of the critical CSS classes * that describe the current page, and its state. * This includes classes that describe the following for example: * - Current language * - Language direction * - YUI CSS initialisation * - Pagelayout * These are commonly used in CSS to target specific types of pages. */ protected function initialise_standard_body_classes() { global $CFG, $USER; $pagetype = $this->pagetype; if ($pagetype == 'site-index') { $this->_legacyclass = 'course'; } else { if (substr($pagetype, 0, 6) == 'admin-') { $this->_legacyclass = 'admin'; } } $this->add_body_class($this->_legacyclass); $pathbits = explode('-', trim($pagetype)); for ($i = 1; $i < count($pathbits); $i++) { $this->add_body_class('path-' . join('-', array_slice($pathbits, 0, $i))); } $this->add_body_classes(core_useragent::get_browser_version_classes()); $this->add_body_class('dir-' . get_string('thisdirection', 'langconfig')); $this->add_body_class('lang-' . current_language()); $this->add_body_class('yui-skin-sam'); // Make YUI happy, if it is used. $this->add_body_class('yui3-skin-sam'); // Make YUI3 happy, if it is used. $this->add_body_class($this->url_to_class_name($CFG->wwwroot)); // Extra class describing current page layout. $this->add_body_class('pagelayout-' . $this->_pagelayout); if (!during_initial_install()) { $this->add_body_class('course-' . $this->_course->id); $this->add_body_class('context-' . $this->_context->id); } if (!empty($this->_cm)) { $this->add_body_class('cmid-' . $this->_cm->id); } if (!empty($CFG->allowcategorythemes)) { $this->ensure_category_loaded(); foreach ($this->_categories as $catid => $notused) { $this->add_body_class('category-' . $catid); } } else { $catid = 0; if (is_array($this->_categories)) { $catids = array_keys($this->_categories); $catid = reset($catids); } else { if (!empty($this->_course->category)) { $catid = $this->_course->category; } } if ($catid) { $this->add_body_class('category-' . $catid); } } if (!isloggedin()) { $this->add_body_class('notloggedin'); } if (!empty($USER->editing)) { $this->add_body_class('editing'); if (optional_param('bui_moveid', false, PARAM_INT)) { $this->add_body_class('blocks-moving'); } } if (!empty($CFG->blocksdrag)) { $this->add_body_class('drag'); } if ($this->_devicetypeinuse != 'default') { $this->add_body_class($this->_devicetypeinuse . 'theme'); } // Add class for behat site to apply behat related fixes. if (defined('BEHAT_SITE_RUNNING')) { $this->add_body_class('behat-site'); } }
/** * States if the browser is IE by returning properties, otherwise false. */ static protected function ie_properties() { $properties = \core_useragent::check_ie_properties(); // In /lib/classes/useragent.php. if (!is_array($properties)) { return false; } else { return $properties; } }
if (!empty($PAGE->theme->settings->persistentedit) && $PAGE->user_allowed_editing()) { if (property_exists($USER, 'editing') && $USER->editing) { $OUTPUT->set_really_editing(true); } $USER->editing = 1; $bodyclasses[] = 'krystle_persistent_edit'; } if (!empty($PAGE->theme->settings->footnote)) { $footnote = $PAGE->theme->settings->footnote; } else { $footnote = '<!-- There was no custom footnote set -->'; } // Tell IE to use the latest engine (no Compatibility mode), if the user is using IE. $ie = false; if (class_exists('core_useragent')) { if (core_useragent::check_ie_version()) { $ie = true; } } else { if (check_browser_version("MSIE", "0")) { $ie = true; } } if ($ie) { header('X-UA-Compatible: IE=edge'); } //Settings for responsive design taken from Zebra theme $userespond = $PAGE->theme->settings->userespond; //Check the theme settings to see if respond.js should be called $usecf = $PAGE->theme->settings->usecf; //Check the theme settings to see if Chrome Frame should be called
/** * Return true if we should look for SVG images as well. * * @return bool */ public function use_svg_icons() { global $CFG; if ($this->usesvg === null) { if (!isset($CFG->svgicons) || !is_bool($CFG->svgicons)) { $this->usesvg = core_useragent::supports_svg(); } else { // Force them on/off depending upon the setting. $this->usesvg = $CFG->svgicons; } } return $this->usesvg; }
if ($themename !== $theme->name) { // Obsoleted or broken theme, just skip for now. continue; } if (empty($CFG->themedesignermode) && $theme->hidefromselector) { // The theme doesn't want to be shown in the theme selector and as theme // designer mode is switched off we will respect that decision. continue; } $strthemename = get_string('pluginname', 'theme_' . $themename); // Build the table row, and also a list of items to go in the second cell. $row = array(); $infoitems = array(); $rowclasses = array(); // Set up bools whether this theme is chosen either main or legacy. $ischosentheme = $themename == core_useragent::get_device_type_theme($device); if ($ischosentheme) { // Is the chosen main theme. $rowclasses[] = 'selectedtheme'; } // Link to the screenshot, now mandatory - the image path is hardcoded because we need image from other themes, // not the current one. $screenshotpath = new moodle_url('/theme/image.php', array('theme' => $themename, 'image' => 'screenshot', 'component' => 'theme')); // Contents of the first screenshot/preview cell. $row[] = html_writer::empty_tag('img', array('src' => $screenshotpath, 'alt' => $strthemename)); // Contents of the second cell. $infocell = $OUTPUT->heading($strthemename, 3); if ($themelocked) { $infocell .= html_writer::div(get_string('configoverride', 'admin'), 'alert alert-info'); } // Button to choose this as the main theme or unset this theme for devices other then default.
/** * Returns one or several CSS class names that match the user's browser. These can be put * in the body tag of the page to apply browser-specific rules without relying on CSS hacks * * @deprecated since 2.6 * @return array An array of browser version classes */ function get_browser_version_classes() { debugging('get_browser_version_classes has been deprecated, please update your code to use core_useragent instead.', DEBUG_DEVELOPER); return core_useragent::get_browser_version_classes(); }