tinyMCE.init({
{$tinymceconfig}
schema: 'html4',
extended_valid_elements : "object[width|height|classid|codebase],param[name|value],embed[src|type|width|height|flashvars|wmode],script[src,type,language],+ul[id|type|compact],iframe[src|width|height|align|title|class|type|frameborder|allowfullscreen]",
urlconverter_callback : "custom_urlconvert",
language: '{$language}',
directionality: "{$tinymce_langdir}",
content_css : {$content_css},
remove_script_host: false,
relative_urls: false,
{$extramceconfig}
setup: function(ed) {
ed.on('init', function(ed) {
if (typeof(editor_to_focus) == 'string' && ed.editorId == editor_to_focus) {
ed.focus();
}
});
ed.on('LoadContent', function(e) {
// Hide all the 2nd/3rd row menu buttons
jQuery('.mce-toolbar.mce-first').siblings().toggleClass('hidden');
// The tinymce fullscreen mode does not work properly in a transformed container div
// such as div.vertcentre
// and IE doesn't like a preset z-index
// This work-around will remove/add classes: .vertcenter .configure .blockinstane
// of the configure block div
// when toggling fullscreen
jQuery('div[aria-label="Fullscreen"]').on('click', function(e) {
jQuery('div#configureblock').toggleClass('vertcentre');
jQuery('div#configureblock').toggleClass('blockinstance');
jQuery('div#configureblock').toggleClass('configure');
});
});
{$extrasetup}
}
});
function imageBrowserConfigSuccess(form, data) {
// handle updates to file browser
// final form submission handled by tinymce plugin
if (data.formelementsuccess) {
eval(data.formelementsuccess + '(form, data)');
return;
}
}
function imageBrowserConfigError(form, data) {
if (data.formelementerror) {
eval(data.formelementerror + '(form, data)');
return;
}
}
function custom_urlconvert (u, n, e) {
// Don't convert the url on the skype status buttons.
if (u.indexOf('skype:') == 0) {
return u;
}
var t = tinyMCE.activeEditor, s = t.settings;
// Don't convert link href since thats the CSS files that gets loaded into the editor also skip local file URLs
if (!s.convert_urls || (e && e.nodeName == 'LINK') || u.indexOf('file:') === 0)
return u;
// Convert to relative
if (s.relative_urls)
return t.documentBaseURI.toRelative(u);
// Convert to absolute
u = t.documentBaseURI.toAbsolute(u, s.remove_script_host);
return u;
}
EOF;
unset($check[$key]);
}
else {
if ($check[$key] != $found_tinymce) {
log_warn('Two differently configured tinyMCE instances have been asked for on this page! This is not possible');
}
unset($check[$key]);
}
}
// If any page adds jquery explicitly, remove it from the list
if (($key = array_search('jquery', $check)) !== false) {
unset($check[$key]);
}
}
}
else {
if (($key = array_search('tinymce', $javascript)) !== false || ($key = array_search('tinytinymce', $javascript)) !== false) {
unset($javascript[$key]);
}
if (($key = array_search('tinymce', $headers)) !== false || ($key = array_search('tinytinymce', $headers)) !== false) {
unset($headers[$key]);
}
}
if (get_config('developermode') & DEVMODE_UNPACKEDJS) {
$javascript_array[] = $jsroot . 'MochiKit/MochiKit.js';
$javascript_array[] = $jsroot . 'MochiKit/Position.js';
$javascript_array[] = $jsroot . 'MochiKit/Color.js';
$javascript_array[] = $jsroot . 'MochiKit/Visual.js';
$javascript_array[] = $jsroot . 'MochiKit/DragAndDrop.js';
$javascript_array[] = $jsroot . 'MochiKit/Format.js';
}
else {
$javascript_array[] = $jsroot . 'MochiKit/Packed.js';
}
$javascript_array[] = $jsroot . 'keyboardNavigation.js';
//If necessary, load MathJax path
if (get_config('mathjax')) {
$javascript_array[] = get_config('mathjaxpath');
}
$strings = array();
foreach ($pagestrings as $k => $v) {
if (is_array($v)) {
foreach ($v as $tag) {
$strings[$tag] = get_raw_string($tag, $k);
}
}
else {
$strings[$k] = get_raw_string($k, $v);
}
}
$jsstrings = jsstrings();
$themepaths = themepaths();
foreach ($javascript as $jsfile) {
// For now, if there's no path in the js file, assume it's in
// $jsroot and append '.js' to the name. Later we may want to
// ensure all smarty() calls include the full path to the js
// file, with the proper extension.
if (strpos($jsfile, '/') === false) {
$javascript_array[] = $jsroot . $jsfile . '.js';
if (isset($jsstrings[$jsfile])) {
foreach ($jsstrings[$jsfile] as $section => $tags) {
foreach ($tags as $tag) {
$strings[$tag] = get_raw_string($tag, $section);
}
}
}
if (isset($themepaths[$jsfile])) {
foreach ($themepaths[$jsfile] as $themepath) {
$theme_list[$themepath] = $THEME->get_url($themepath);
}
}
}
else if (stripos($jsfile, 'http://') === false && stripos($jsfile, 'https://') === false) {
// A local .js file with a fully specified path
$javascript_array[] = $wwwroot . $jsfile;
// If $jsfile is from a plugin or plugin's block, i.e.:
// - plugintype/pluginname/js/foo.js
// - plugintype/pluginname/blocktype/pluginname/js/foo.js
// Then get js strings from static function jsstrings in:
// - plugintype/pluginname/lib.php, or
// - plugintype/pluginname/blocktype/pluginname/lib.php
$bits = explode('/', $jsfile);
$pluginname = false;
$plugintype = false;
$jsfilename = false;
if (count($bits) == 4 && $bits[2] == 'js' && in_array($bits[0], plugin_types())) {
$plugintype = $bits[0];
$pluginname = $bits[1];
$jsfilename = $bits[3];
}
if (count($bits) == 6 && $bits[0] == 'artefact' && $bits[2] == 'blocktype' && $bits[4] == 'js') {
$plugintype = 'blocktype';
$pluginname = $bits[3];
$jsfilename = $bits[5];
}
if ($pluginname) {
safe_require($plugintype, $pluginname);
$pluginclass = generate_class_name($plugintype, $pluginname);
$name = substr($jsfilename, 0, strpos($jsfilename, '.js'));
if (is_callable(array($pluginclass, 'jsstrings'))) {
$tempstrings = call_static_method($pluginclass, 'jsstrings', $name);
foreach ($tempstrings as $section => $tags) {
foreach ($tags as $tag) {
$strings[$tag] = get_raw_string($tag, $section);
}
}
}
if (is_callable(array($pluginclass, 'jshelp'))) {
$tempstrings = call_static_method($pluginclass, 'jshelp', $name);
foreach ($tempstrings as $section => $tags) {
foreach ($tags as $tag) {
$strings[$tag . '.help'] = get_help_icon($plugintype, $pluginname, null, null,
null, $tag);
}
}
}
if (is_callable(array($pluginclass, 'themepaths'))) {
$tmpthemepaths = call_static_method($pluginclass, 'themepaths', $name);
foreach ($tmpthemepaths as $themepath) {
$theme_list[$themepath] = $THEME->get_url($themepath);
}
}
}
}
else {
// A remote .js file
$javascript_array[] = $jsfile;
}
}
$javascript_array[] = $jsroot . 'mahara.js';
$javascript_array[] = $jsroot . 'formchangechecker.js';
foreach ($jsstrings['mahara'] as $section => $tags) {
foreach ($tags as $tag) {
$strings[$tag] = get_raw_string($tag, $section);
}
}
if (isset($extraconfig['themepaths']) && is_array($extraconfig['themepaths'])) {
foreach ($extraconfig['themepaths'] as $themepath) {
$theme_list[$themepath] = $THEME->get_url($themepath);
}
}
$stringjs = '';
// Allow us to set the HTML lang attribute
$smarty->assign('LANGUAGE', substr(current_language(), 0, 2));
$smarty->assign('STRINGJS', $stringjs);
$stylesheets = get_stylesheets_for_current_page($stylesheets, $extraconfig);
$smarty->assign('STYLESHEETLIST', $stylesheets);
if (!empty($theme_list)) {
// this gets assigned in smarty_core, but do it again here if it's changed locally
$smarty->assign('THEMELIST', json_encode(array_merge((array)json_decode($smarty->get_template_vars('THEMELIST')), $theme_list)));
}
$dropdownmenu = get_config('dropdownmenu');
// disable drop-downs if overridden at institution level
$sitethemeprefs = get_config('sitethemeprefs');
$institutions = $USER->institutions;
if (!empty($institutions)) {
foreach ($institutions as $i) {
if (!empty($sitethemeprefs)) {
if (!empty($USER->accountprefs['theme']) && $USER->accountprefs['theme'] == $THEME->basename . '/' . $i->institution) {
$dropdownmenu = $i->dropdownmenu;
}
}
else {
if ((!empty($USER->accountprefs['theme']) && $USER->accountprefs['theme'] == $THEME->basename . '/' . $i->institution)
|| (empty($USER->accountprefs) && $i->theme == $THEME->basename && $USER->institutiontheme->institutionname == $i->institution)) {
$dropdownmenu = $i->dropdownmenu;
}
}
}
}
// and/or disable drop-downs if a handheld device detected
$dropdownmenu = $SESSION->get('handheld_device') ? false : $dropdownmenu;
if ($dropdownmenu) {
$smarty->assign('DROPDOWNMENU', $dropdownmenu);
$javascript_array[] = $jsroot . 'dropdown-nav.js';
}
$smarty->assign('MOBILE', $SESSION->get('mobile'));
$smarty->assign('HANDHELD_DEVICE', $SESSION->get('handheld_device'));
$sitename = get_config('sitename');
if (!$sitename) {
$sitename = 'Mahara';
}
$smarty->assign('sitename', $sitename);
$sitelogo = $THEME->header_logo();
$sitelogo = append_version_number($sitelogo);
$smarty->assign('sitelogo', $sitelogo);
$smarty->assign('sitelogo4facebook', $THEME->facebook_logo());
$smarty->assign('sitedescription4facebook', get_string('facebookdescription', 'mahara'));
if (defined('TITLE')) {
$smarty->assign('PAGETITLE', TITLE . ' - ' . $sitename);
$smarty->assign('heading', TITLE);
}
else {
$smarty->assign('PAGETITLE', $sitename);
}
$smarty->assign('PRODUCTIONMODE', get_config('productionmode'));
if (function_exists('local_header_top_content')) {
$sitetop = (isset($sitetop) ? $sitetop : '') . local_header_top_content();
}
if (isset($sitetop)) {
$smarty->assign('SITETOP', $sitetop);
}
if (defined('PUBLIC')) {
$smarty->assign('PUBLIC', true);
}
if (defined('ADMIN')) {
$smarty->assign('ADMIN', true);
}
if (defined('INSTITUTIONALADMIN')) {
$smarty->assign('INSTITUTIONALADMIN', true);
}
if (defined('STAFF')) {
$smarty->assign('STAFF', true);
}
if (defined('INSTITUTIONALSTAFF')) {
$smarty->assign('INSTITUTIONALSTAFF', true);
}
$smarty->assign('LOGGEDIN', $USER->is_logged_in());
$publicsearchallowed = false;
$searchplugin = get_config('searchplugin');
if ($searchplugin) {
safe_require('search', $searchplugin);
$publicsearchallowed = (call_static_method(generate_class_name('search', $searchplugin), 'publicform_allowed') && get_config('publicsearchallowed'));
}
$smarty->assign('publicsearchallowed', $publicsearchallowed);
if ($USER->is_logged_in()) {
global $SELECTEDSUBNAV; // It's evil, but rightnav & mainnav stuff are now in different templates.
$smarty->assign('MAINNAV', main_nav());
$mainnavsubnav = $SELECTEDSUBNAV;
$smarty->assign('RIGHTNAV', right_nav());
if (!$mainnavsubnav && $dropdownmenu) {
// In drop-down navigation, the submenu is only usable if its parent is one of the top-level menu
// items. But if the submenu comes from something in right_nav (settings), it's unreachable.
// Turning the submenu into SUBPAGENAV group-style tabs makes it usable.
$smarty->assign('SUBPAGENAV', $SELECTEDSUBNAV);
}
else {
$smarty->assign('SELECTEDSUBNAV', $SELECTEDSUBNAV);
}
}
else {
$smarty->assign('languageform', $langselectform);
}
$smarty->assign('FOOTERMENU', footer_menu());
$smarty->assign_by_ref('USER', $USER);
$smarty->assign('SESSKEY', $USER->get('sesskey'));
$smarty->assign('CC_ENABLED', get_config('cookieconsent_enabled'));
$javascript_array = append_version_number($javascript_array);
$smarty->assign_by_ref('JAVASCRIPT', $javascript_array);
$smarty->assign('RELEASE', get_config('release'));
$smarty->assign('SERIES', get_config('series'));
$smarty->assign('CACHEVERSION', get_config('cacheversion'));
$siteclosedforupgrade = get_config('siteclosed');
if ($siteclosedforupgrade && get_config('disablelogin')) {
$smarty->assign('SITECLOSED', 'logindisabled');
}
else if ($siteclosedforupgrade || get_config('siteclosedbyadmin')) {
$smarty->assign('SITECLOSED', 'loginallowed');
}
if ((!isset($extraconfig['pagehelp']) || $extraconfig['pagehelp'] !== false)
and $help = has_page_help()) {
$smarty->assign('PAGEHELPNAME', $help[0]);
$smarty->assign('PAGEHELPICON', $help[1]);
}
if (defined('GROUP')) {
require_once('group.php');
if ($group = group_current_group()) {
$smarty->assign('GROUP', $group);
if (!defined('NOGROUPMENU')) {
$smarty->assign('SUBPAGENAV', group_get_menu_tabs());
$smarty->assign('PAGEHEADING', $group->name);
}
}
}
// ---------- sideblock stuff ----------
$sidebars = !isset($extraconfig['sidebars']) || $extraconfig['sidebars'] !== false;
if ($sidebars && !defined('INSTALLER') && (!defined('MENUITEM') || substr(MENUITEM, 0, 5) != 'admin')) {
if (get_config('installed') && !$adminsection) {
$data = site_menu();
if (!empty($data)) {
$smarty->assign('SITEMENU', site_menu());
$sideblocks[] = array(
'name' => 'linksandresources',
'weight' => 10,
'data' => $data,
);
}
}
if ($USER->is_logged_in() && defined('MENUITEM') &&
(substr(MENUITEM, 0, 11) == 'myportfolio' || substr(MENUITEM, 0, 7) == 'content')) {
if (get_config('showselfsearchsideblock')) {
$sideblocks[] = array(
'name' => 'selfsearch',
'weight' => 0,
'data' => array(),
);
}
if (get_config('showtagssideblock')) {
$sideblocks[] = array(
'name' => 'tags',
'id' => 'sb-tags',
'weight' => 0,
'data' => tags_sideblock(),
);
}
}
if ($USER->is_logged_in() && !$adminsection) {
$sideblocks[] = array(
'name' => 'profile',
'id' => 'sb-profile',
'class' => 'user-panel',
'weight' => -20,
'data' => profile_sideblock()
);
$showusers = 2;
$institutions = $USER->institutions;
if (!empty($institutions)) {
$showusers = 0;
foreach ($institutions as $i) {
if ($i->showonlineusers == 2) {
$showusers = 2;
break;
}
if ($i->showonlineusers == 1) {
$showusers = 1;
}
}
}
if (get_config('showonlineuserssideblock') && $showusers > 0) {
$sideblocks[] = array(
'name' => 'onlineusers',
'id' => 'sb-onlineusers',
'weight' => -10,
'data' => onlineusers_sideblock(),
);
}
if (get_config('showprogressbar') && $USER->get_account_preference('showprogressbar')) {
$sideblocks[] = array(
'name' => 'progressbar',
'id' => 'sb-progressbar',
'class' => 'progressbar',
'weight' => -8,
'data' => progressbar_sideblock(),
);
}
}
if ($USER->is_logged_in() && $adminsection && defined('SECTION_PAGE') && SECTION_PAGE == 'progressbar') {
$sideblocks[] = array(
'name' => 'progressbar',
'id' => 'sb-progressbar',
'class' => 'progressbar',
'weight' => -8,
'data' => progressbar_sideblock(true),
);
}
$isloginblockvisible = !$USER->is_logged_in() && !(get_config('siteclosed') && get_config('disablelogin'))
&& get_config('showloginsideblock');
if ($isloginblockvisible) {
$sideblocks[] = array(
'name' => 'login',
'weight' => -10,
'id' => 'sb-loginbox',
'data' => array(
'loginform' => auth_generate_login_form(),
),
);
}
if (get_config('enablenetworking')) {
require_once(get_config('docroot') .'api/xmlrpc/lib.php');
if ($USER->is_logged_in() && $ssopeers = get_service_providers($USER->authinstance)) {
$sideblocks[] = array(
'name' => 'ssopeers',
'weight' => 1,
'data' => $ssopeers,
);
}
}
if (isset($extraconfig['sideblocks']) && is_array($extraconfig['sideblocks'])) {
foreach ($extraconfig['sideblocks'] as $sideblock) {
$sideblocks[] = $sideblock;
}
}
// local_sideblocks_update allows sites to customise the sideblocks by munging the $sideblocks array.
if (function_exists('local_sideblocks_update')) {
local_sideblocks_update($sideblocks);
}
usort($sideblocks, create_function('$a,$b', 'if ($a["weight"] == $b["weight"]) return 0; return ($a["weight"] < $b["weight"]) ? -1 : 1;'));
// Place all sideblocks on the right. If this structure is munged
// appropriately, you can put blocks on the left. In future versions of
// Mahara, we'll make it easy to do this.
$sidebars = $sidebars && !empty($sideblocks);
$sideblocks = array('left' => array(), 'right' => $sideblocks);
$smarty->assign('userauthinstance', $SESSION->get('authinstance'));
$smarty->assign('MNETUSER', $SESSION->get('mnetuser'));
$smarty->assign('SIDEBLOCKS', $sideblocks);
$smarty->assign('SIDEBARS', $sidebars);
}
if (is_array($HEADDATA) && !empty($HEADDATA)) {
$headers = array_merge($HEADDATA, $headers);
}
$smarty->assign_by_ref('HEADERS', $headers);
if ($USER->get('parentuser')) {
$smarty->assign('USERMASQUERADING', true);
$smarty->assign('masqueradedetails', get_string('youaremasqueradingas', 'mahara', display_name($USER)));
$smarty->assign('becomeyoulink', hsc($wwwroot) . 'admin/users/changeuser.php?restore=1');
$smarty->assign('becomeyouagain', get_string('becomeadminagain', 'admin', hsc($USER->get('parentuser')->name)));
}
// Define additional html content
if (get_config('installed')) {
$additionalhtmlitems = array(
'ADDITIONALHTMLHEAD' => get_config('additionalhtmlhead'),
'ADDITIONALHTMLTOPOFBODY' => get_config('additionalhtmltopofbody'),
'ADDITIONALHTMLFOOTER' => get_config('additionalhtmlfooter')
);
if ($additionalhtmlitems) {
foreach ($additionalhtmlitems as $name=>$content) {
$smarty->assign($name, $content);
}
}
}
// If Cookie Consent is enabled, than define conent
if (get_config('cookieconsent_enabled')) {
require_once('cookieconsent.php');
$smarty->assign('COOKIECONSENTCODE', get_cookieconsent_code());
}
return $smarty;
}
/**
* Manages theme configuration.
*
* Does its best to give the user _a_ theme, even if it's not the theme they
* want to use (e.g. the theme they want has been uninstalled)
*/
class Theme {
/**
* The base name of the theme (the name of the directory in which it lives)
*/
public $basename = '';
/**
* A user may have had the header logo overridden by an institution
*/
public $headerlogo;
/**
* Additional stylesheets to display after the basename theme's stylesheets
*/
public $addedstylesheets;
/**
* A human-readable version of the theme name
*/
public $displayname = '';
/**
* Which pieform renderer to use by default for all forms
*/
public $formrenderer = '';
/**
* Directories where to look for templates by default
*/
public $templatedirs = array();
/**
* Theme inheritance path from this theme to 'raw'
*/
public $inheritance = array();
/**
* What unit the left/center/right column widths are in. 'pixels' or 'percent'
*/
public $columnwidthunits = '';
/**
* Width of the left column. Integer - see $columnwidthunits
*/
public $leftcolumnwidth = 256;
/**
* Background colour for the left column
*/
public $leftcolumnbgcolor = '#fff';
/**
* Background colour for the center column
*/
public $centercolumnbgcolor = '#fff';
/**
* Width of the right column. Integer - see $columnwidthunits
*/
public $rightcolumnwidth = 256;
/**
* Background colour for the right column
*/
public $rightcolumnbgcolor = '#fff';
/**
* If the theme can use the svg image file format.
*/
public $usesvg = false;
/**
* Initialises a theme object based on the theme 'hint' passed.
*
* If arg is a string, it's taken to be a theme name. If it's a user
* object, we ask it for a theme name. If it's an integer, we pretend
* that's a user ID and ask for the theme for that user.
*
* If the theme they want doesn't exist, the object is initialised for the
* default theme. This means you can initialise one of these for a user
* and then use it without worrying if the theme exists.
*
* @param mixed $arg Theme name, user object or user ID
*/
public function __construct($arg) {
if (is_string($arg)) {
$themename = $arg;
$themedata = null;
}
else if ($arg instanceof User) {
$themedata = $arg->get_themedata();
}
else if (is_int($arg)) {
$user = new User();
$user->find_by_id($arg);
$themedata = $user->get_themedata();
}
else {
throw new SystemException("Argument to Theme::__construct was not a theme name, user object or user ID");
}
if (isset($themedata)) {
$themename = $themedata->basename;
}
if (empty($themename)) {
// Theme to show to when no theme has been suggested
if (!$themename = get_config('theme')) {
$themename = 'raw';
}
}
// check the validity of the name
if (!$this->name_is_valid($themename)) {
throw new SystemException("Theme name is in invalid form: '$themename'");
}
$this->init_theme($themename, $themedata);
}
/**
* Given a theme name, check that it is valid
*/
public static function name_is_valid($themename) {
// preg_match returns 0 if invalid characters were found, 1 if not
return (preg_match('/^[a-zA-Z0-9_-]+$/', $themename) == 1);
}
/**
* Given a theme name, reads in all config and sets fields on this object
*/
private function init_theme($themename, $themedata) {
// A little anonymous function to retrieve *only* the $theme variable from
// the themeconfig.php file
$getthemeconfig = function($themename) {
$themeconfigfile = get_config('docroot') . 'theme/' . $themename . '/themeconfig.php';
if (is_readable($themeconfigfile)) {
require( get_config('docroot') . 'theme/' . $themename . '/themeconfig.php' );
return $theme;
}
else {
return false;
}
};
$themeconfig = $getthemeconfig($themename);
if (!$themeconfig) {
// We can safely assume that the default theme is installed, users
// should never be able to remove it
$themename ='default';
$themeconfig = $getthemeconfig($themename);
}
$this->basename = $themename;
foreach (get_object_vars($themeconfig) as $key => $value) {
$this->$key = $value;
}
if (!isset($this->displayname)) {
$this->displayname = $this->basename;
}
// Local theme overrides come first
$this->templatedirs[] = get_config('docroot') . 'local/theme/templates/';
// Then the current theme
$this->templatedirs[] = get_config('docroot') . 'theme/' . $this->basename . '/templates/';
$this->inheritance[] = $this->basename;
// 'raw' is the default parent theme
// (If a theme has no parent, it should set $themeconfig->parent = false)
if (!isset($themeconfig->parent)) {
$themeconfig->parent = 'raw';
}
$currentthemename = $this->basename;
while ($themeconfig->parent !== false) {
// Now go through the theme hierarchy assigning variables from the
// parent themes
$parentthemename = $themeconfig->parent;
$parentthemeconfig = $getthemeconfig($parentthemename);
// If the parent theme is missing, short-circuit to the "raw" theme
if (!$parentthemeconfig) {
log_warn("Theme \"{$currentthemename}\" has missing parent theme \"{$parentthemename}\".");
$parentthemename = 'raw';
$parentthemeconfig = $getthemeconfig($parentthemename);
}
$currentthemename = $parentthemename;
$themeconfig = $parentthemeconfig;
foreach (get_object_vars($themeconfig) as $key => $value) {
if (!isset($this->$key) || !$this->$key) {
$this->$key = $value;
}
}
$this->templatedirs[] = get_config('docroot') . 'theme/' . $currentthemename . '/templates/';
$this->inheritance[] = $currentthemename;
if (!isset($themeconfig->parent)) {
$themeconfig->parent = 'raw';
}
}
if (!empty($themedata->headerlogo)) {
$this->headerlogo = $themedata->headerlogo;
}
if (!empty($themedata->stylesheets)) {
$this->addedstylesheets = $themedata->stylesheets;
}
}
/**
* Get the URL of a particular theme asset (i.e. an image or CSS file). Checks first for a copy
* in /local/theme/static, then in the current theme, then this theme's parent, grandparent, etc.
*
* @param string $filename Relative path of the asset, e.g. 'images/newmail.png'
* @param boolean $all Whether to return the first found copy of the asset, or all copies of it from all themes
* in the hierarchy.
* @param string $plugindirectory For if it's a plugin theme asset, e.g. 'artefact/file'
* @return string|array The URL of the first match, or all matching ones, depending on $all
*/
public function get_url($filename, $all=false, $plugindirectory='') {
return $this->_get_path($filename, $all, $plugindirectory, get_config('wwwroot'));
}
/**
* Get the full filesystem path of a particular theme asset (i.e. an image or CSS file). Checks first for a copy
* in /local/theme/static, then in the current theme, then this theme's parent, grandparent, etc.
*
* @param string $filename Relative path of the asset, e.g. 'images/newmail.png'
* @param boolean $all Whether to return the first found copy of the asset, or all copies it from all
* themes in the hierarchy
* @param string $plugindirectory For if it's a plugin theme asset, e.g. 'artefact/file'
* @return string|array The full filesystem path of the first match, or of all matches, depending on $all
*/
public function get_path($filename, $all=false, $plugindirectory='') {
return $this->_get_path($filename, $all, $plugindirectory, get_config('docroot'));
}
/**
* Internal function to return the path or URL of a particular theme asset. Relies on the fact that the URL
* and the filesystem path are the same, except that one is prefaced by docroot and the other by wwwroot.
*
* @param string $filename Relative path of the asset, e.g. 'images/newmail.png'
* @param boolean $all Whether to return the first found copy of the asset, or all copies it from all
* themes in the hierarchy
* @param string $plugindirectory For if it's a plugin theme asset, e.g. 'artefact/file'
* @param string $returnprefix The part to put before the Mahara-relative path of the file. (i.e. docroot or wwwroot)
* @param boolean $debug If a debug message is added to log.
* @return string|array The first match, or of all matches, depending on $all
*/
private function _get_path($filename, $all, $plugindirectory, $returnprefix, $debug=true) {
$list = array();
if ($plugindirectory) {
// If they provided a plugindirectory, make sure it ends with a slash
// (this will save us some if-thens down the road)
$basepluginpath = $plugindirectory;
if (substr($basepluginpath, -1) != '/') {
// $basepluginpath is the relative path of the plugin, i.e. blocktype/creativecommons
$basepluginpath = $basepluginpath . '/';
}
// $pluginpath is the path to the plugin in a theme context, i.e. with "plugintype" in front
$pluginpath = "plugintype/{$basepluginpath}";
}
else {
$basepluginpath = $pluginpath = '';
}
// Local theme overrides come first
$searchpaths = array(
'local' => array(
"local/theme/{$pluginpath}{$filename}",
"local/theme/{$basepluginpath}static/{$filename}"
),
);
// Then check each theme
foreach ($this->inheritance as $themedir) {
$searchloc = array();
// Check in the /theme directory
$searchloc[] = "theme/{$themedir}/{$pluginpath}{$filename}";
$searchloc[] = "theme/{$themedir}/{$basepluginpath}static/{$filename}";
if ($basepluginpath) {
// Then check in the plugin's own directory
$searchloc[] = "{$basepluginpath}theme/{$themedir}/{$filename}";
$searchloc[] = "{$basepluginpath}theme/{$themedir}/static/{$filename}";
}
$searchpaths[$themedir] = $searchloc;
}
// Check for the file in each searchpath
foreach ($searchpaths as $theme => $searchloc) {
foreach ($searchloc as $loc) {
if (is_readable(get_config('docroot') . $loc)) {
if ($all) {
$list[$theme] = $returnprefix . $loc;
}
else {
return $returnprefix . $loc;
}
}
}
}
if ($all) {
return $list;
}
if ($debug) {
$this->log_debug_missing_file($filename, $plugindirectory);
}
return $returnprefix . $basepluginpath . 'theme/' . $themedir . '/' . $filename;
}
/**
* Log debug when a file is missing.
*
* @param string $filename Relative path of the asset, e.g. 'images/newmail.png'
* @param string $plugindirectory For if it's a plugin theme asset, e.g. 'artefact/file'
* @param string $message The message prefix of the log debug.
*/
private function log_debug_missing_file($filename, $plugindirectory='', $message='Missing file in theme') {
$extra = '';
if (!empty($plugindirectory)) {
$extra = ", plugindir $plugindirectory";
}
log_debug("$message {$this->basename}{$extra}: $filename");
}
/**
* Displaying of the header logo of an institution
* If $name is specified the site-logo-[$name].png will be returned
* The site logo will be returned if no institution logo is found and $name is not specified
*/
public function header_logo($name = false) {
if (!empty($this->headerlogo)) {
return get_config('wwwroot') . 'thumb.php?type=logobyid&id=' . $this->headerlogo;
}
else if ($name) {
return $this->get_image_url('site-logo-' . $name);
}
else {
try {
$sitelogoid = get_field('institution', 'logo', 'name', 'mahara');
if ($sitelogoid) {
return get_config('wwwroot') . 'thumb.php?type=logobyid&id=' . $sitelogoid;
}
}
catch (SQLException $e) {
// Probably the site hasn't been installed or upgraded yet.
}
}
return $this->get_image_url('site-logo');
}
public function facebook_logo() {
return $this->get_image_url('site-logo4facebook');
}
public function additional_stylesheets() {
return $this->addedstylesheets;
}
/**
* Adds the URL of an image by trying differents extensions.
* Searching for svg, png, gif and jpg in last.
*
* @param string $filename The name of the file without the extension and the images folder.
* @param string $plugindirectory The plugin directory.
* @return string The image URL with the correct file extension.
*/
public function get_image_url($filename, $plugindirectory = '') {
$loc = '';
$extensions = array('png', 'gif', 'jpg');
// Only use the svg image file format if the theme allow it.
if ($this->usesvg) {
array_unshift($extensions, 'svg');
}
// Check for all images extension in the correct order.
foreach ($extensions as $ext) {
$temploc = $this->_get_path("images/$filename.$ext", false, $plugindirectory, '', false);
if (is_readable(get_config('docroot') . $temploc)) {
$loc = $temploc;
break;
}
}
// If no image found, log the debug message and return the last non-existing image format.
if (empty($loc)) {
$this->log_debug_missing_file($filename, $plugindirectory, 'Missing image file in theme');
$loc = $temploc;
}
return get_config('wwwroot') . $loc;
}
}
/**
* Returns the lists of strings used in the .js files
* @return array
*/
function jsstrings() {
return array(
'mahara' => array( // js file
'mahara' => array( // section
'namedfieldempty', // string name
'processing',
'unknownerror',
'loading',
'showtags',
'couldnotgethelp',
'password',
'deleteitem',
'moveitemup',
'moveitemdown',
'username',
'login',
'sessiontimedout',
'loginfailed',
'home',
'youhavenottaggedanythingyet',
'wanttoleavewithoutsaving?',
'Help',
'closehelp',
'tabs',
'toggletoolbarson',
'toggletoolbarsoff',
'imagexofy',
),
'pieforms' => array(
'element.calendar.opendatepicker'
)
),
'tablerenderer' => array(
'mahara' => array(
'firstpage',
'nextpage',
'prevpage',
'lastpage',
)
),
'views' => array(
'view' => array(
'confirmdeleteblockinstance',
'blocksinstructionajax',
),
),
);
}
function themepaths() {
static $paths;
if (empty($paths)) {
$paths = array(
'mahara' => array(
),
);
}
return $paths;
}
/**
* Takes an array of string identifiers and returns an array of the
* corresponding strings, quoted for use in inline javascript here
* docs.
*/
function quotestrings($strings) {
$qstrings = array();
foreach ($strings as $section => $tags) {
foreach ($tags as $tag) {
$qstrings[$tag] = json_encode(get_string($tag, $section));
}
}
return $qstrings;
}
/**
* This function sets up and caches info about the current selected theme
* contains inheritance path (used for locating images) and template dirs
* and potentially more stuff later ( like mime header to send (html vs xhtml))
* @return object
*/
function theme_setup() {
global $THEME;
log_warn("theme_setup() is deprecated - please use the global \$THEME object instead");
return $THEME;
}
/**
* This function returns the full url to an image
* Always use it to get image urls
* @param $imagelocation path to image relative to theme/$theme/
* @param $pluginlocation path to plugin relative to docroot
*/
function theme_get_url($location, $pluginlocation='', $all = false) {
global $THEME;
log_warn("theme_get_url() is deprecated: Use \$THEME->get_url() instead");
$plugintype = $pluginname = '';
if ($pluginlocation) {
list($plugintype, $pluginname) = explode('/', $pluginlocation);
$pluginname = substr($pluginname, 0, -1);
}
return $THEME->get_url($location, $all, $plugintype, $pluginname);
}
/**
* This function returns the full path to an image
* Always use it to get image paths
* @param $imagelocation path to image relative to theme/$theme/
* @param $pluginlocation path to plugin relative to docroot
*/
function theme_get_path($location, $pluginlocation='', $all=false) {
global $THEME;
log_warn("theme_get_path() is deprecated: Use \$THEME->get_path() instead");
$plugintype = $pluginname = '';
if ($pluginlocation) {
list($plugintype, $pluginname) = explode('/', $pluginlocation);
$pluginname = substr($pluginname, 0, -1);
}
return $THEME->get_path($location, $all, $plugintype, $pluginname);
}
/**
* This function sends headers suitable for all JSON returning scripts.
*
*/
function json_headers() {
header('Content-type: application/json');
header('Pragma: no-cache');
}
/**
* This function sends a JSON message, and ends the script.
*
* Scripts receiving replies will recieve a JSON array with two fields:
*
* - error: True or false depending on whether the request was successful
* - message: JSON data representing a message sent back from the script
*
* @param boolean $error Whether the script ended in an error or not
* @param string $message A message to pass back to the user, can be an
* array of JSON data
*/
function json_reply($error, $message, $returncode=0) {
json_headers();
echo json_encode(array('error' => $error, 'message' => $message, 'returnCode' => $returncode));
perf_to_log();
exit;
}
function _param_retrieve($name) {
// prefer post
if (isset($_POST[$name])) {
$value = $_POST[$name];
}
else if (isset($_GET[$name])) {
$value = $_GET[$name];
}
else if (func_num_args() == 2) {
$php_work_around = func_get_arg(1);
return array($php_work_around, true);
}
else {
throw new ParameterException("Missing parameter '$name' and no default supplied");
}
return array($value, false);
}
function param_exists($name) {
return isset($_POST[$name]) || isset($_GET[$name]);
}
/**
* This function returns a GET or POST parameter with optional default. If the
* default isn't specified and the parameter hasn't been sent, a
* ParameterException exception is thrown
*
* @param string The GET or POST parameter you want returned
* @param mixed [optional] the default value for this parameter
*
* @return string The value of the parameter
*
*/
function param_variable($name) {
$args = func_get_args();
list ($value) = call_user_func_array('_param_retrieve', $args);
return $value;
}
/**
* This function returns a GET or POST parameter as an integer with optional
* default. If the default isn't specified and the parameter hasn't been sent,
* a ParameterException exception is thrown. Likewise, if the parameter isn't a
* valid integer, a ParameterException exception is thrown
*
* @param string The GET or POST parameter you want returned
* @param mixed [optional] the default value for this parameter
*
* @return int The value of the parameter
*
*/
function param_integer($name) {
$args = func_get_args();
list ($value, $defaultused) = call_user_func_array('_param_retrieve', $args);
if ($defaultused) {
return $value;
}
$value = trim($value);
if (preg_match('/^\d+$/',$value)) {
return (int)$value;
}
else if ($value == '' && isset($args[1])) {
return $args[1];
}
throw new ParameterException("The '$name' parameter is not an integer");
}
/**
* This function returns a GET or POST parameter as an integer with optional
* default. If the default isn't specified and the parameter hasn't been sent,
* a ParameterException exception is thrown. Likewise, if the parameter isn't a
* valid integer(allows signed integers), a ParameterException exception is thrown
*
* @param string The GET or POST parameter you want returned
* @param mixed [optional] the default value for this parameter
*
* @return int The value of the parameter
*
*/
function param_signed_integer($name) {
$args = func_get_args();
list ($value, $defaultused) = call_user_func_array('_param_retrieve', $args);
if ($defaultused) {
return $value;
}
$value = trim($value);
if (preg_match('/^[+-]?[0-9]+$/', $value)) {
return (int)$value;
}
else if ($value == '' && isset($args[1])) {
return $args[1];
}
throw new ParameterException("The '$name' parameter is not an integer");
}
/**
* This function returns a GET or POST parameter as an alpha string with optional
* default. If the default isn't specified and the parameter hasn't been sent,
* a ParameterException exception is thrown. Likewise, if the parameter isn't a
* valid alpha string, a ParameterException exception is thrown
*
* Valid characters are a-z and A-Z
*
* @param string The GET or POST parameter you want returned
* @param mixed [optional] the default value for this parameter
*
* @return string The value of the parameter
*
*/
function param_alpha($name) {
$args = func_get_args();
list ($value, $defaultused) = call_user_func_array('_param_retrieve', $args);
if ($defaultused) {
return $value;
}
$value = trim($value);
if (preg_match('/^[a-zA-Z]+$/',$value)) {
return $value;
}
throw new ParameterException("The '$name' parameter is not alphabetical only");
}
/**
* This function returns a GET or POST parameter as an alphanumeric string with optional
* default. If the default isn't specified and the parameter hasn't been sent,
* a ParameterException exception is thrown. Likewise, if the parameter isn't a
* valid alpha string, a ParameterException exception is thrown
*
* Valid characters are a-z and A-Z and 0-9
*
* @param string The GET or POST parameter you want returned
* @param mixed [optional] the default value for this parameter
*
* @return string The value of the parameter
*
*/
function param_alphanum($name) {
$args = func_get_args();
list ($value, $defaultused) = call_user_func_array('_param_retrieve', $args);
if ($defaultused) {
return $value;
}
$value = trim($value);
if (preg_match('/^[a-zA-Z0-9]+$/',$value)) {
return $value;
}
throw new ParameterException("The '$name' parameter is not alphanumeric only");
}
/**
* This function returns a GET or POST parameter as an alphanumeric string with optional
* default. If the default isn't specified and the parameter hasn't been sent,
* a ParameterException exception is thrown. Likewise, if the parameter isn't a
* valid alpha string, a ParameterException exception is thrown
*
* Valid characters are a-z and A-Z and 0-9 and _ and - and .
*
* @param string The GET or POST parameter you want returned
* @param mixed [optional] the default value for this parameter
*
* @return string The value of the parameter
*
*/
function param_alphanumext($name) {
$args = func_get_args();
list ($value, $defaultused) = call_user_func_array('_param_retrieve', $args);
if ($defaultused) {
return $value;
}
$value = trim($value);
if (preg_match('/^[a-zA-Z0-9_.-]+$/',$value)) {
return $value;
}
throw new ParameterException("The '$name' parameter contains invalid characters");
}
/**
* This function returns a GET or POST parameter as an array of integers with optional
* default. If the default isn't specified and the parameter hasn't been sent,
* a ParameterException exception is thrown. Likewise, if the parameter isn't a
* valid integer list , a ParameterException exception is thrown.
*
* An integer list is integers separated by commas (with optional whitespace),
* or just whitespace which indicates an empty list
*
* @param string The GET or POST parameter you want returned
* @param mixed [optional] the default value for this parameter
*
* @return array The value of the parameter
*
*/
function param_integer_list($name) {
$args = func_get_args();
list ($value, $defaultused) = call_user_func_array('_param_retrieve', $args);
if ($defaultused) {
return $value;
}
$value = trim($value);
if ($value == '') {
return array();
}
if (preg_match('/^(\d+(\s*,\s*\d+)*)$/',$value)) {
return array_map('intval', explode(',', $value));
}
throw new ParameterException("The '$name' parameter is not an integer list");
}
/**
* This function returns a GET or POST parameter as a boolean.
*
* @param string The GET or POST parameter you want returned
*
* @return bool The value of the parameter
*
*/
function param_boolean($name) {
list ($value) = _param_retrieve($name, false);
if (!is_null($value)) {
$value = trim($value);
}
if (empty($value) || $value == 'off' || $value == 'no' || $value == 'false') {
return false;
}
else {
return true;
}
}
/**
* NOTE: this function is only meant to be used by get_imagesize_parameters(),
* which you should use in your scripts.
*
* It expects the parameter to be a string, in the form /\d+x\d+/ - e.g.
* 200x150.
*
* @param string The GET or POST parameter you want checked
* TODO: i18n for the error messages
*/
function param_imagesize($name) {
$args = func_get_args();
list ($value, $defaultused) = call_user_func_array('_param_retrieve', $args);
if ($defaultused) {
return $value;
}
$value = trim($value);
if (!preg_match('/\d+x\d+/', $value)) {
throw new ParameterException('Invalid size for image specified');
}
return $value;
}
/**
* Works out what size a requested image should be, based on request parameters
*
* The result of this function can be passed to get_dataroot_image_path to
* retrieve the filesystem path of the appropriate image
*/
function get_imagesize_parameters($sizeparam='size', $widthparam='width', $heightparam='height',
$maxsizeparam='maxsize', $maxwidthparam='maxwidth', $maxheightparam='maxheight') {
$size = param_imagesize($sizeparam, '');
$width = param_integer($widthparam, 0);
$height = param_integer($heightparam, 0);
$maxsize = param_integer($maxsizeparam, 0);
$maxwidth = param_integer($maxwidthparam, 0);
$maxheight = param_integer($maxheightparam, 0);
return imagesize_data_to_internal_form($size, $width, $height, $maxsize, $maxwidth, $maxheight);
}
/**
* Given sizing information, converts it to a form that get_dataroot_image_path
* can use.
*
* @param mixed $size either an array with 'w' and 'h' keys, or a string 'WxH'.
* Image will be exactly this size
* @param int $width Width. Image will be scaled to be exactly this wide
* @param int $height Height. Image will be scaled to be exactly this high
* @param int $maxsize The longest side will be scaled to be this size
* @param int $maxwidth Use with maxheight - image dimensions will be made as
* large as possible but not exceed either one
* @param int $maxheight Use with maxwidth - image dimensions will be made as
* large as possible but not exceed either one
* @return mixed A sizing parameter that can be used with get_dataroot_image_path()
*/
function imagesize_data_to_internal_form($size, $width, $height, $maxsize, $maxwidth, $maxheight) {
$imagemaxwidth = get_config('imagemaxwidth');
$imagemaxheight = get_config('imagemaxheight');
if ($size) {
if (is_array($size)) {
if (isset($size['w']) && isset($size['h'])) {
$width = $size['w'];
$height = $size['h'];
}
else {
throw new ParameterException('Size parameter is corrupt');
}
}
else if (is_string($size)) {
list($width, $height) = explode('x', $size);
}
else {
throw new ParameterException('Size parameter is corrupt');
}
if ($width > get_config('imagemaxwidth') || $height > get_config('imagemaxheight')) {
throw new ParameterException('Requested image size is too big');
}
if ($width < 16 || $height < 16) {
throw new ParameterException('Requested image size is too small');
}
return array('w' => $width, 'h' => $height);
}
if ($maxsize) {
if ($maxsize > $imagemaxwidth && $maxsize > $imagemaxheight) {
throw new ParameterException('Requested image size is too big');
}
if ($maxsize < 16) {
throw new ParameterException('Requested image size is too small');
}
return $maxsize;
}
if ($width) {
if ($width > $imagemaxwidth) {
throw new ParameterException('Requested image size is too big');
}
if ($width < 16) {
throw new ParameterException('Requested image size is too small');
}
return array('w' => $width);
}
if ($height) {
if ($height > $imagemaxheight) {
throw new ParameterException('Requested image size is too big');
}
if ($height < 16) {
throw new ParameterException('Requested image size is too small');
}
return array('h' => $height);
}
$max = array();
if ($maxwidth) {
if ($maxwidth > $imagemaxwidth) {
throw new ParameterException('Requested image size is too big');
}
if ($maxwidth < 16) {
throw new ParameterException('Requested image size is too small');
}
$max['maxw'] = $maxwidth;
}
if ($maxheight) {
if ($maxheight > $imagemaxheight) {
throw new ParameterException('Requested image size is too big');
}
if ($maxheight < 16) {
throw new ParameterException('Requested image size is too small');
}
$max['maxh'] = $maxheight;
}
if (!empty($max)) {
return $max;
}
return null;
}
/**
* Gets a cookie, respecting the configured cookie prefix
*
* @param string $name The name of the cookie to get the value of
* @return string The value of the cookie, or null if the cookie does not
* exist.
*/
function get_cookie($name) {
$name = get_config('cookieprefix') . $name;
return (isset($_COOKIE[$name])) ? $_COOKIE[$name] : null;
}
function get_cookies($prefix) {
static $prefixes = array();
if (!isset($prefixes[$prefix])) {
$prefixes[$prefix] = array();
$cprefix = get_config('cookieprefix') . $prefix;
foreach ($_COOKIE as $k => $v) {
if (strpos($k, $cprefix) === 0) {
$prefixes[$prefix][substr($k, strlen($cprefix))] = $v;
}
}
}
return $prefixes[$prefix];
}
/**
* Sets a cookie, respecting the configured cookie prefix
*
* @param string $name The name of the cookie
* @param string $value The value for the cookie
* @param int $expires The unix timestamp of the time the cookie should expire
*/
function set_cookie($name, $value='', $expires=0, $access=false) {
$name = get_config('cookieprefix') . $name;
$url = parse_url(get_config('wwwroot'));
if (!$domain = get_config('cookiedomain')) {
$domain = $url['host'];
}
// If Cookie Consent is enabled with cc_necessary cookie set to 'yes'
// or Cookie Consent is not enabled
if (empty($_COOKIE['cc_necessary']) || (isset($_COOKIE['cc_necessary']) && $_COOKIE['cc_necessary'] == 'yes')) {
setcookie($name, $value, $expires, $url['path'], $domain, is_https(), true);
}
if ($access) { // View access cookies may be needed on this request
$_COOKIE[$name] = $value;
}
}
/**
* Returns an assoc array of countrys suitable for use with the "select" form
* element
*
* @return array Associative array of countrycodes => countrynames
*/
function getoptions_country() {
static $countries;
if (!empty($countries)) {
return $countries;
}
$codes = array(
'af',
'ax',
'al',
'dz',
'as',
'ad',
'ao',
'ai',
'aq',
'ag',
'ar',
'am',
'aw',
'au',
'at',
'az',
'bs',
'bh',
'bd',
'bb',
'by',
'be',
'bz',
'bj',
'bm',
'bt',
'bo',
'ba',
'bw',
'bv',
'br',
'io',
'bn',
'bg',
'bf',
'bi',
'kh',
'cm',
'ca',
'cv',
'ky',
'cf',
'td',
'cl',
'cn',
'cx',
'cc',
'co',
'km',
'cg',
'cd',
'ck',
'cr',
'ci',
'hr',
'cu',
'cy',
'cz',
'dk',
'dj',
'dm',
'do',
'ec',
'eg',
'sv',
'gq',
'er',
'ee',
'et',
'fk',
'fo',
'fj',
'fi',
'fr',
'gf',
'pf',
'tf',
'ga',
'gm',
'ge',
'de',
'gh',
'gi',
'gr',
'gl',
'gd',
'gp',
'gu',
'gt',
'gg',
'gn',
'gw',
'gy',
'ht',
'hm',
'va',
'hn',
'hk',
'hu',
'is',
'in',
'id',
'ir',
'iq',
'ie',
'im',
'il',
'it',
'jm',
'jp',
'je',
'jo',
'kz',
'ke',
'ki',
'kp',
'kr',
'kw',
'kg',
'la',
'lv',
'lb',
'ls',
'lr',
'ly',
'li',
'lt',
'lu',
'mo',
'mk',
'mg',
'mw',
'my',
'mv',
'ml',
'mt',
'mh',
'mq',
'mr',
'mu',
'yt',
'mx',
'fm',
'md',
'mc',
'mn',
'ms',
'ma',
'mz',
'mm',
'na',
'nr',
'np',
'nl',
'an',
'nc',
'nz',
'ni',
'ne',
'ng',
'nu',
'nf',
'mp',
'no',
'om',
'pk',
'pw',
'ps',
'pa',
'pg',
'py',
'pe',
'ph',
'pn',
'pl',
'pt',
'pr',
'qa',
're',
'ro',
'ru',
'rw',
'sh',
'kn',
'lc',
'pm',
'vc',
'ws',
'sm',
'st',
'sa',
'sn',
'cs',
'sc',
'sl',
'sg',
'sk',
'si',
'sb',
'so',
'za',
'gs',
'es',
'lk',
'sd',
'sr',
'sj',
'sz',
'se',
'ch',
'sy',
'tw',
'tj',
'tz',
'th',
'tl',
'tg',
'tk',
'to',
'tt',
'tn',
'tr',
'tm',
'tc',
'tv',
'ug',
'ua',
'ae',
'gb',
'us',
'um',
'uy',
'uz',
'vu',
've',
'vn',
'vg',
'vi',
'wf',
'eh',
'ye',
'zm',
'zw',
);
foreach ($codes as $c) {
$countries[$c] = get_string("country.{$c}");
};
uasort($countries, 'strcoll');
return $countries;
}
/**
* Returns an HTML string with a help icon image that can be used on a page.
* When the icon is clicked, a dialog box will be shown with contextual help
* for the element or page the icon is connected to.
*
* All parameters except $title determine where the help text will be found.
* For example:
*
* // Returns the help text in artefact/blog/lang/[lang]/help/forms/editpost.draft.html
* get_help_icon('artefact', 'blog', 'editpost', 'draft');
* // Returns the help text in artefact/internal/lang/[lang]/help/pages/index.html
* get_help_icon('artefact', 'internal', '', '', 'index');
*
*
* @param string $plugintype the type of plugin to find help text for
* @param string $pluginname the name of the plugin to find help text for
* @param string $form the ID of the form this help icon is connected to
* @param string $element the ID of the form element this help icon is connected to
* @param string $page the page this help icon describes
* @param string $section the section this help icon describes
* @param string $title the title/label of the element this help icon is connected to
*
* @return string HTML with help icon element
*/
function get_help_icon($plugintype, $pluginname, $form, $element, $page='', $section='', $title=null) {
global $THEME;
if ($title) {
$content = get_string('helpfor', 'mahara', $title);
}
else {
$content = get_string('Help');
}
return ' '. $content . '';
}
function pieform_get_help(Pieform $form, $element) {
$plugintype = isset($element['helpplugintype']) ? $element['helpplugintype'] : $form->get_property('plugintype');
$pluginname = isset($element['helppluginname']) ? $element['helppluginname'] : $form->get_property('pluginname');
$formname = isset($element['helpformname']) ? $element['helpformname'] : $form->get_name();
return get_help_icon($plugintype, $pluginname, $formname, $element['name'], '', '', (isset($element['title']) ? $element['title'] : null));
}
/**
* Is this a page in the admin area?
*
* @return bool
*/
function in_admin_section() {
return defined('ADMIN') || defined('INSTITUTIONALADMIN') || defined('STAFF') || defined('INSTITUTIONALSTAFF') || defined('INADMINMENU');
}
/**
* Returns the entries in the standard admin menu
*
* See the function find_menu_children() in lib/web.php
* for a description of the expected array structure.
*
* @return $adminnav a data structure containing the admin navigation
*/
function admin_nav() {
$menu = array(
'adminhome' => array(
'path' => 'adminhome',
'url' => 'admin/index.php',
'title' => get_string('adminhome', 'admin'),
'weight' => 10,
'accesskey' => 'a',
),
'adminhome/home' => array(
'path' => 'adminhome/home',
'url' => 'admin/index.php',
'title' => get_string('overview'),
'weight' => 10,
),
'adminhome/registersite' => array(
'path' => 'adminhome/registersite',
'url' => 'admin/registersite.php',
'title' => get_string('register'),
'weight' => 20,
),
'adminhome/statistics' => array(
'path' => 'adminhome/statistics',
'url' => 'admin/statistics.php',
'title' => get_string('sitestatistics', 'admin'),
'weight' => 30,
),
'configsite' => array(
'path' => 'configsite',
'url' => 'admin/site/options.php',
'title' => get_string('configsite', 'admin'),
'weight' => 20,
'accesskey' => 'c',
),
'configsite/siteoptions' => array(
'path' => 'configsite/siteoptions',
'url' => 'admin/site/options.php',
'title' => get_string('siteoptions', 'admin'),
'weight' => 10,
),
'configsite/sitepages' => array(
'path' => 'configsite/sitepages',
'url' => 'admin/site/pages.php',
'title' => get_string('staticpages', 'admin'),
'weight' => 20
),
'configsite/sitemenu' => array(
'path' => 'configsite/sitemenu',
'url' => 'admin/site/menu.php',
'title' => get_string('menus', 'admin'),
'weight' => 30,
),
'configsite/networking' => array(
'path' => 'configsite/networking',
'url' => 'admin/site/networking.php',
'title' => get_string('networking', 'admin'),
'weight' => 40,
),
'configsite/sitelicenses' => array(
'path' => 'configsite/sitelicenses',
'url' => 'admin/site/licenses.php',
'title' => get_string('sitelicenses', 'admin'),
'weight' => 45,
),
'configsite/siteviews' => array(
'path' => 'configsite/siteviews',
'url' => 'admin/site/views.php',
'title' => get_string('Views', 'view'),
'weight' => 50,
),
'configsite/collections' => array(
'path' => 'configsite/collections',
'url' => 'collection/index.php?institution=mahara',
'title' => get_string('Collections', 'collection'),
'weight' => 60,
),
'configsite/share' => array(
'path' => 'configsite/share',
'url' => 'admin/site/shareviews.php',
'title' => get_string('share', 'view'),
'weight' => 70,
),
'configsite/sitefiles' => array(
'path' => 'configsite/sitefiles',
'url' => 'artefact/file/sitefiles.php',
'title' => get_string('Files', 'artefact.file'),
'weight' => 80,
),
'configsite/cookieconsent' => array(
'path' => 'configsite/cookieconsent',
'url' => 'admin/site/cookieconsent.php',
'title' => get_string('cookieconsent', 'cookieconsent'),
'weight' => 90,
),
'configusers' => array(
'path' => 'configusers',
'url' => 'admin/users/search.php',
'title' => get_string('users'),
'weight' => 30,
'accesskey' => 'u',
),
'configusers/usersearch' => array(
'path' => 'configusers/usersearch',
'url' => 'admin/users/search.php',
'title' => get_string('usersearch', 'admin'),
'weight' => 10,
),
'configusers/suspendedusers' => array(
'path' => 'configusers/suspendedusers',
'url' => 'admin/users/suspended.php',
'title' => get_string('suspendeduserstitle', 'admin'),
'weight' => 15,
),
'configusers/staffusers' => array(
'path' => 'configusers/staffusers',
'url' => 'admin/users/staff.php',
'title' => get_string('sitestaff', 'admin'),
'weight' => 20,
),
'configusers/adminusers' => array(
'path' => 'configusers/adminusers',
'url' => 'admin/users/admins.php',
'title' => get_string('siteadmins', 'admin'),
'weight' => 30,
),
'configusers/exportqueue' => array(
'path' => 'configusers/exportqueue',
'url' => 'admin/users/exportqueue.php',
'title' => get_string('exportqueue', 'admin'),
'weight' => 35,
),
'configusers/adduser' => array(
'path' => 'configusers/adduser',
'url' => 'admin/users/add.php',
'title' => get_string('adduser', 'admin'),
'weight' => 40,
),
'configusers/uploadcsv' => array(
'path' => 'configusers/uploadcsv',
'url' => 'admin/users/uploadcsv.php',
'title' => get_string('uploadcsv', 'admin'),
'weight' => 50,
),
'managegroups' => array(
'path' => 'managegroups',
'url' => 'admin/groups/groups.php',
'title' => get_string('groups', 'admin'),
'accessibletitle' => get_string('administergroups', 'admin'),
'weight' => 40,
'accesskey' => 'g',
),
'managegroups/groups' => array(
'path' => 'managegroups/groups',
'url' => 'admin/groups/groups.php',
'title' => get_string('administergroups', 'admin'),
'weight' => 10,
),
'managegroups/categories' => array(
'path' => 'managegroups/categories',
'url' => 'admin/groups/groupcategories.php',
'title' => get_string('groupcategories', 'admin'),
'weight' => 20,
),
'managegroups/archives' => array(
'path' => 'managegroups/archives',
'url' => 'admin/groups/archives.php',
'title' => get_string('archivedsubmissions', 'admin'),
'weight' => 25,
),
'managegroups/uploadcsv' => array(
'path' => 'managegroups/uploadcsv',
'url' => 'admin/groups/uploadcsv.php',
'title' => get_string('uploadgroupcsv', 'admin'),
'weight' => 30,
),
'managegroups/uploadmemberscsv' => array(
'path' => 'managegroups/uploadmemberscsv',
'url' => 'admin/groups/uploadmemberscsv.php',
'title' => get_string('uploadgroupmemberscsv', 'admin'),
'weight' => 40,
),
'manageinstitutions' => array(
'path' => 'manageinstitutions',
'url' => 'admin/users/institutions.php',
'title' => get_string('Institutions', 'admin'),
'weight' => 50,
'accesskey' => 'i',
),
'manageinstitutions/institutions' => array(
'path' => 'manageinstitutions/institutions',
'url' => 'admin/users/institutions.php',
'title' => get_string('Institutions', 'admin'),
'weight' => 10,
),
'manageinstitutions/sitepages' => array(
'path' => 'manageinstitutions/sitepages',
'url' => 'admin/users/institutionpages.php',
'title' => get_string('staticpages', 'admin'),
'weight' => 15
),
'manageinstitutions/institutionusers' => array(
'path' => 'manageinstitutions/institutionusers',
'url' => 'admin/users/institutionusers.php',
'title' => get_string('Members', 'admin'),
'weight' => 20,
),
'manageinstitutions/institutionstaff' => array(
'path' => 'manageinstitutions/institutionstaff',
'url' => 'admin/users/institutionstaff.php',
'title' => get_string('Staff', 'admin'),
'weight' => 30,
),
'manageinstitutions/institutionadmins' => array(
'path' => 'manageinstitutions/institutionadmins',
'url' => 'admin/users/institutionadmins.php',
'title' => get_string('Admins', 'admin'),
'weight' => 40,
),
'manageinstitutions/adminnotifications' => array(
'path' => 'manageinstitutions/adminnotifications',
'url' => 'admin/users/notifications.php',
'title' => get_string('adminnotifications', 'admin'),
'weight' => 50,
),
'manageinstitutions/progressbar' => array(
'path' => 'manageinstitutions/progressbar',
'url' => 'admin/users/progressbar.php',
'title' => get_string('progressbar', 'admin'),
'weight' => 55,
),
'manageinstitutions/institutionviews' => array(
'path' => 'manageinstitutions/institutionviews',
'url' => 'view/institutionviews.php',
'title' => get_string('Views', 'view'),
'weight' => 60,
),
'manageinstitutions/institutioncollections' => array(
'path' => 'manageinstitutions/institutioncollections',
'url' => 'collection/index.php?institution=1',
'title' => get_string('Collections', 'collection'),
'weight' => 70,
),
'manageinstitutions/share' => array(
'path' => 'manageinstitutions/share',
'url' => 'view/institutionshare.php',
'title' => get_string('share', 'view'),
'weight' => 80,
),
'manageinstitutions/institutionfiles' => array(
'path' => 'manageinstitutions/institutionfiles',
'url' => 'artefact/file/institutionfiles.php',
'title' => get_string('Files', 'artefact.file'),
'weight' => 90,
),
'manageinstitutions/statistics' => array(
'path' => 'manageinstitutions/statistics',
'url' => 'admin/users/statistics.php',
'title' => get_string('statistics', 'admin'),
'weight' => 100,
),
'manageinstitutions/pendingregistrations' => array(
'path' => 'manageinstitutions/pendingregistrations',
'url' => 'admin/users/pendingregistrations.php',
'title' => get_string('pendingregistrations', 'admin'),
'weight' => 110,
),
'configextensions' => array(
'path' => 'configextensions',
'url' => 'admin/extensions/plugins.php',
'title' => get_string('Extensions', 'admin'),
'weight' => 60,
'accesskey' => 'e',
),
'configextensions/pluginadmin' => array(
'path' => 'configextensions/pluginadmin',
'url' => 'admin/extensions/plugins.php',
'title' => get_string('pluginadmin', 'admin'),
'weight' => 10,
),
'configextensions/filters' => array(
'path' => 'configextensions/filters',
'url' => 'admin/extensions/filter.php',
'title' => get_string('htmlfilters', 'admin'),
'weight' => 20,
),
'configextensions/iframesites' => array(
'path' => 'configextensions/iframesites',
'url' => 'admin/extensions/iframesites.php',
'title' => get_string('allowediframesites', 'admin'),
'weight' => 30,
),
'configextensions/cleanurls' => array(
'path' => 'configextensions/cleanurls',
'url' => 'admin/extensions/cleanurls.php',
'title' => get_string('cleanurls', 'admin'),
'weight' => 40,
),
);
// Add the menu items for skins, if that feature is enabled
if (get_config('skins')) {
$menu['configsite/siteskins'] = array(
'path' => 'configsite/siteskins',
'url' => 'admin/site/skins.php',
'title' => get_string('siteskinmenu', 'skin'),
'weight' => 75,
);
$menu['configsite/sitefonts'] = array(
'path' => 'configsite/sitefonts',
'url' => 'admin/site/fonts.php',
'title' => get_string('sitefontsmenu', 'skin'),
'weight' => 76,
);
}
// enable plugins to augment the admin menu structure
foreach (array('artefact', 'interaction', 'module', 'auth') as $plugintype) {
if ($plugins = plugins_installed($plugintype)) {
foreach ($plugins as &$plugin) {
if (safe_require_plugin($plugintype, $plugin->name)) {
$plugin_menu = call_static_method(generate_class_name($plugintype,$plugin->name), 'admin_menu_items');
$menu = array_merge($menu, $plugin_menu);
}
}
}
}
return $menu;
}
/**
* Returns the entries in the standard institutional admin menu
*
* See the function find_menu_children() in lib/web.php
* for a description of the expected array structure.
*
* @return $adminnav a data structure containing the admin navigation
*/
function institutional_admin_nav() {
global $USER;
$ret = array(
'configusers' => array(
'path' => 'configusers',
'url' => 'admin/users/search.php',
'title' => get_string('users'),
'weight' => 10,
'accesskey' => 'u',
),
'configusers/usersearch' => array(
'path' => 'configusers/usersearch',
'url' => 'admin/users/search.php',
'title' => get_string('usersearch', 'admin'),
'weight' => 10,
),
'configusers/suspendedusers' => array(
'path' => 'configusers/suspendedusers',
'url' => 'admin/users/suspended.php',
'title' => get_string('suspendeduserstitle', 'admin'),
'weight' => 20,
),
'configusers/exportqueue' => array(
'path' => 'configusers/exportqueue',
'url' => 'admin/users/exportqueue.php',
'title' => get_string('exportqueue', 'admin'),
'weight' => 25,
),
'configusers/adduser' => array(
'path' => 'configusers/adduser',
'url' => 'admin/users/add.php',
'title' => get_string('adduser', 'admin'),
'weight' => 30,
),
'configusers/uploadcsv' => array(
'path' => 'configusers/uploadcsv',
'url' => 'admin/users/uploadcsv.php',
'title' => get_string('uploadcsv', 'admin'),
'weight' => 40,
),
'managegroups' => array(
'path' => 'managegroups',
'url' => 'admin/groups/uploadcsv.php',
'title' => get_string('groups', 'admin'),
'accessibletitle' => get_string('administergroups', 'admin'),
'weight' => 20,
'accesskey' => 'g',
),
'managegroups/archives' => array(
'path' => 'managegroups/archives',
'url' => 'admin/groups/archives.php',
'title' => get_string('archivedsubmissions', 'admin'),
'weight' => 5,
),
'managegroups/uploadcsv' => array(
'path' => 'managegroups/uploadcsv',
'url' => 'admin/groups/uploadcsv.php',
'title' => get_string('uploadgroupcsv', 'admin'),
'weight' => 10,
),
'managegroups/uploadmemberscsv' => array(
'path' => 'managegroups/uploadmemberscsv',
'url' => 'admin/groups/uploadmemberscsv.php',
'title' => get_string('uploadgroupmemberscsv', 'admin'),
'weight' => 20,
),
'manageinstitutions' => array(
'path' => 'manageinstitutions',
'url' => 'admin/users/institutions.php',
'title' => get_string('Institutions', 'admin'),
'weight' => 30,
'accesskey' => 'i',
),
'manageinstitutions/institutions' => array(
'path' => 'manageinstitutions/institutions',
'url' => 'admin/users/institutions.php',
'title' => get_string('settings'),
'weight' => 10,
),
'manageinstitutions/sitepages' => array(
'path' => 'manageinstitutions/sitepages',
'url' => 'admin/users/institutionpages.php',
'title' => get_string('staticpages', 'admin'),
'weight' => 15
),
'manageinstitutions/institutionusers' => array(
'path' => 'manageinstitutions/institutionusers',
'url' => 'admin/users/institutionusers.php',
'title' => get_string('Members', 'admin'),
'weight' => 20,
),
'manageinstitutions/institutionstaff' => array(
'path' => 'manageinstitutions/institutionstaff',
'url' => 'admin/users/institutionstaff.php',
'title' => get_string('Staff', 'admin'),
'weight' => 30,
),
'manageinstitutions/institutionadmins' => array(
'path' => 'manageinstitutions/institutionadmins',
'url' => 'admin/users/institutionadmins.php',
'title' => get_string('Admins', 'admin'),
'weight' => 40,
),
'manageinstitutions/adminnotifications' => array(
'path' => 'manageinstitutions/adminnotifications',
'url' => 'admin/users/notifications.php',
'title' => get_string('adminnotifications', 'admin'),
'weight' => 50,
),
'manageinstitutions/institutionviews' => array(
'path' => 'manageinstitutions/institutionviews',
'url' => 'view/institutionviews.php',
'title' => get_string('Views', 'view'),
'weight' => 60,
),
'manageinstitutions/institutioncollections' => array(
'path' => 'manageinstitutions/institutioncollections',
'url' => 'collection/index.php?institution=1',
'title' => get_string('Collections', 'collection'),
'weight' => 70,
),
'manageinstitutions/share' => array(
'path' => 'manageinstitutions/share',
'url' => 'view/institutionshare.php',
'title' => get_string('share', 'view'),
'weight' => 80,
),
'manageinstitutions/institutionfiles' => array(
'path' => 'manageinstitutions/institutionfiles',
'url' => 'artefact/file/institutionfiles.php',
'title' => get_string('Files', 'artefact.file'),
'weight' => 90,
),
'manageinstitutions/statistics' => array(
'path' => 'manageinstitutions/statistics',
'url' => 'admin/users/statistics.php',
'title' => get_string('statistics', 'admin'),
'weight' => 100,
),
'manageinstitutions/pendingregistrations' => array(
'path' => 'manageinstitutions/pendingregistrations',
'url' => 'admin/users/pendingregistrations.php',
'title' => get_string('pendingregistrations', 'admin'),
'weight' => 110,
),
);
if ($USER->get('staff')) {
$ret['adminhome'] = array(
'path' => 'adminhome',
'url' => 'admin/statistics.php',
'title' => get_string('site', 'admin'),
'weight' => 40,
'accesskey' => 'a',
);
$ret['adminhome/statistics'] = array(
'path' => 'adminhome/statistics',
'url' => 'admin/statistics.php',
'title' => get_string('statistics', 'admin'),
'weight' => 10,
);
};
// enable plugins to augment the institution admin menu structure
foreach (array('artefact', 'interaction', 'module', 'auth') as $plugintype) {
if ($plugins = plugins_installed($plugintype)) {
foreach ($plugins as &$plugin) {
if (safe_require_plugin($plugintype, $plugin->name)) {
$plugin_menu = call_static_method(generate_class_name($plugintype,$plugin->name), 'institution_menu_items');
$ret = array_merge($ret, $plugin_menu);
}
}
}
}
return $ret;
}
/**
* Returns the entries in the staff menu
*
* See the function find_menu_children() in lib/web.php
* for a description of the expected array structure.
*
* @return a data structure containing the staff navigation
*/
function staff_nav() {
$menu = array(
'usersearch' => array(
'path' => 'usersearch',
'url' => 'admin/users/search.php',
'title' => get_string('usersearch', 'admin'),
'weight' => 10,
'accesskey' => 'u',
),
'statistics' => array(
'path' => 'statistics',
'url' => 'admin/statistics.php',
'title' => get_string('sitestatistics', 'admin'),
'weight' => 20,
'accesskey' => 's',
),
'institutionalstatistics' => array(
'path' => 'statistics',
'url' => 'admin/users/statistics.php',
'title' => get_string('institutionstatistics', 'admin'),
'weight' => 30,
'accesskey' => 'i',
),
);
// enable plugins to augment the institution staff menu structure
foreach (array('artefact', 'interaction', 'module', 'auth') as $plugintype) {
if ($plugins = plugins_installed($plugintype)) {
foreach ($plugins as &$plugin) {
if (safe_require_plugin($plugintype, $plugin->name)) {
$plugin_menu = call_static_method(generate_class_name($plugintype,$plugin->name), 'institution_staff_menu_items');
$menu = array_merge($menu, $plugin_menu);
}
}
}
}
return $menu;
}
/**
* Returns the entries in the institutional staff menu
*
* See the function find_menu_children() in lib/web.php
* for a description of the expected array structure.
*
* @return a data structure containing the institutional staff navigation
*/
function institutional_staff_nav() {
return array(
'usersearch' => array(
'path' => 'usersearch',
'url' => 'admin/users/search.php',
'title' => get_string('usersearch', 'admin'),
'weight' => 10,
'accesskey' => 'u',
),
'institutionalstatistics' => array(
'path' => 'statistics',
'url' => 'admin/users/statistics.php',
'title' => get_string('institutionstatistics', 'admin'),
'weight' => 20,
'accesskey' => 'i',
),
);
}
/**
* Returns the entries in the standard user menu
*
* See the function find_menu_children() in lib/web.php
* for a description of the expected array structure.
*
* @return $standardnav a data structure containing the standard navigation
*/
function mahara_standard_nav() {
global $SESSION;
$exportenabled = (plugins_installed('export') && !$SESSION->get('handheld_device')) ? TRUE : FALSE;
$menu = array(
'home' => array(
'path' => 'home',
'url' => '',
'title' => get_string('dashboard', 'view'),
'weight' => 10,
'accesskey' => 'd',
),
'content' => array(
'path' => 'content',
'url' => 'artefact/internal/index.php', // @todo possibly do path aliasing and dispatch?
'title' => get_string('Content'),
'weight' => 20,
'accesskey' => 'c',
),
'myportfolio' => array(
'path' => 'myportfolio',
'url' => 'view/index.php',
'title' => get_string('myportfolio'),
'weight' => 30,
'accesskey' => 'p',
),
'myportfolio/views' => array(
'path' => 'myportfolio/views',
'url' => 'view/index.php',
'title' => get_string('Views', 'view'),
'weight' => 10,
),
'myportfolio/share' => array(
'path' => 'myportfolio/share',
'url' => 'view/share.php',
'title' => get_string('sharedbyme', 'view'),
'weight' => 30,
),
'myportfolio/sharedviews' => array(
'path' => 'myportfolio/sharedviews',
'url' => 'view/sharedviews.php',
'title' => get_string('sharedwithme', 'view'),
'weight' => 60,
),
'myportfolio/export' => array(
'path' => 'myportfolio/export',
'url' => 'export/index.php',
'title' => get_string('Export', 'export'),
'weight' => 70,
'ignore' => !$exportenabled,
),
'myportfolio/import' => array(
'path' => 'myportfolio/import',
'url' => 'import/index.php',
'title' => get_string('Import', 'import'),
'weight' => 80,
),
'myportfolio/collection' => array(
'path' => 'myportfolio/collection',
'url' => 'collection/index.php',
'title' => get_string('Collections', 'collection'),
'weight' => 20,
),
'groups' => array(
'path' => 'groups',
'url' => 'group/mygroups.php',
'title' => get_string('groups'),
'weight' => 40,
'accesskey' => 'g',
),
'groups/mygroups' => array(
'path' => 'groups/mygroups',
'url' => 'group/mygroups.php',
'title' => get_string('mygroups'),
'weight' => 10,
),
'groups/find' => array(
'path' => 'groups/find',
'url' => 'group/find.php',
'title' => get_string('findgroups'),
'weight' => 20,
),
'groups/myfriends' => array(
'path' => 'groups/myfriends',
'url' => 'user/myfriends.php',
'title' => get_string('myfriends'),
'weight' => 30,
),
'groups/findfriends' => array(
'path' => 'groups/findfriends',
'url' => 'user/find.php',
'title' => get_string('findfriends'),
'weight' => 40,
),
'groups/institutionmembership' => array(
'path' => 'groups/institutions',
'url' => 'account/institutions.php',
'title' => get_string('institutionmembership'),
'weight' => 50,
),
);
if (can_use_skins()) {
$menu['myportfolio/skins'] = array(
'path' => 'myportfolio/skins',
'url' => 'skin/index.php',
'title' => get_string('myskins', 'skin'),
'weight' => 65,
);
}
return $menu;
}
/**
* Builds a data structure representing the menu for Mahara.
*
* @return array
*/
function main_nav() {
global $USER;
$language = current_language();
$cachemenu = false;
// Get the first institution
$institution = $USER->get_primary_institution();
$menutype = '';
if (in_admin_section()) {
global $USER, $SESSION;
if ($USER->get('admin')) {
$menutype = 'admin_nav';
if (!($cachemenu = get_config_institution($institution, $menutype . '_' . $language))) {
$menu = admin_nav();
}
}
else if ($USER->is_institutional_admin()) {
$menutype = 'instadmin_nav';
if (!($cachemenu = get_config_institution($institution, $menutype . '_' . $language))) {
$menu = institutional_admin_nav();
}
}
else if ($USER->get('staff')) {
$menutype = 'staff_nav';
if (!($cachemenu = get_config_institution($institution, $menutype . '_' . $language))) {
$menu = staff_nav();
}
}
else {
$menutype = 'inststaff_nav';
if (!($cachemenu = get_config_institution($institution, $menutype . '_' . $language))) {
$menu = institutional_staff_nav();
}
}
}
else {
// Build the menu structure for the site
$menutype = 'standard_nav';
if (!($cachemenu = get_config_institution($institution, $menutype . '_' . $language))) {
$menu = mahara_standard_nav();
}
}
if ($cachemenu) {
$menu = json_decode($cachemenu, true);
}
else {
$menu = array_filter($menu, create_function('$a', 'return empty($a["ignore"]);'));
// enable plugins to augment the menu structure
foreach (array('artefact', 'interaction', 'module', 'auth') as $plugintype) {
if ($plugins = plugins_installed($plugintype)) {
foreach ($plugins as &$plugin) {
if (safe_require_plugin($plugintype, $plugin->name)) {
$plugin_menu = call_static_method(generate_class_name($plugintype,$plugin->name), 'menu_items');
$menu = array_merge($menu, $plugin_menu);
}
}
}
}
set_config_institution($institution, $menutype . '_' . $language, json_encode($menu));
}
// local_main_nav_update allows sites to customise the menu by munging the $menu array.
// as there is no internal way to know if the local_main_nav array has changed we keep it outside the cached menu
if (function_exists('local_main_nav_update')) {
local_main_nav_update($menu);
}
$menu_structure = find_menu_children($menu, '');
return $menu_structure;
}
/**
* Clear the cached menu so that the next visit to the site will recreate the cache.
*
* @param string $institution Optional institution name if we only want to delete cache from a certain institution
*/
function clear_menu_cache($institution = null) {
if ($institution) {
try {
delete_records_sql("DELETE FROM {institution_config} WHERE field LIKE '%/_nav/_%' ESCAPE '/' AND institution = ?", array($institution));
}
catch (SQLException $e) {
// Institution_config table may not exist on install/upgrade at this point
}
}
else {
try {
delete_records_sql("DELETE FROM {institution_config} WHERE field LIKE '%/_nav/_%' ESCAPE '/'", array());
}
catch (SQLException $e) {
// Institution_config table may not exist on install/upgrade at this point
}
}
}
function right_nav() {
global $USER, $THEME;
safe_require('notification', 'internal');
$unread = $USER->get('unread');
$menu = array(
'settings' => array(
'path' => 'settings',
'url' => 'account/index.php',
'title' => get_string('settings'),
'alt' => '',
'weight' => 10,
'iconclass' => 'cogs'
),
'inbox' => array(
'path' => 'inbox',
'url' => 'account/activity/index.php',
'title' => get_string('inbox'),
'alt' => get_string('inbox'),
'count' => $unread,
'countclass' => 'unreadmessagecount',
'linkid' => 'mail',
'weight' => 20,
'iconclass' => 'envelope'
),
'settings/account' => array(
'path' => 'settings/account',
'url' => 'account/index.php',
'title' => get_config('dropdownmenu') ? get_string('general') : get_string('account'),
'weight' => 10,
'iconclass' => 'user'
),
'settings/notifications' => array(
'path' => 'settings/notifications',
'url' => 'account/activity/preferences/index.php',
'title' => get_string('notifications'),
'weight' => 30,
'iconclass' => 'flag'
),
);
// enable plugins to augment the menu structure
foreach (array('artefact', 'interaction', 'module') as $plugintype) {
if ($plugins = plugins_installed($plugintype)) {
foreach ($plugins as &$plugin) {
if (safe_require_plugin($plugintype, $plugin->name)) {
$plugin_nav_menu = call_static_method(generate_class_name($plugintype, $plugin->name),
'right_nav_menu_items');
$menu = array_merge($menu, $plugin_nav_menu);
}
}
}
}
// local_right_nav_update allows sites to customise the menu by munging the $menu array.
if (function_exists('local_right_nav_update')) {
local_right_nav_update($menu);
}
$menu_structure = find_menu_children($menu, '');
return $menu_structure;
}
function footer_menu($all=false) {
$wwwroot = get_config('wwwroot');
$menu = array(
'termsandconditions' => array(
'url' => $wwwroot . 'terms.php',
'title' => get_string('termsandconditions'),
),
'privacystatement' => array(
'url' => $wwwroot . 'privacy.php',
'title' => get_string('privacystatement'),
),
'about' => array(
'url' => $wwwroot . 'about.php',
'title' => get_string('about'),
),
'contactus' => array(
'url' => $wwwroot . 'contact.php',
'title' => get_string('contactus'),
),
);
if ($all) {
return $menu;
}
if ($enabled = get_config('footerlinks')) {
$enabled = unserialize($enabled);
foreach ($menu as $k => $v) {
if (!in_array($k, $enabled)) {
unset($menu[$k]);
}
}
}
if ($customlinks = get_config('footercustomlinks')) {
$customlinks = unserialize($customlinks);
foreach ($customlinks as $k => $v) {
if (!empty($menu[$k])) {
$menu[$k]['url'] = $v;
}
}
}
return $menu;
}
/**
* Given a menu structure and a path, returns a data structure representing all
* of the child menu items of the path, and removes those items from the menu
* structure
*
* The menu structure should be an array. Each item in the array should be
* a sub-array representing one of the nodes in the menu.
*
* The keys of each menu node are as follows:
* path: Where the link sits in the menu. E.g. 'myporfolio/myplugin'
* parent: (optional) The parent path - use if tertiary level menu
* url: The URL to the page, relative to wwwroot. E.g. 'artefact/myplugin/'
* title: Translated text to use for the text of the link. E.g. get_string('myplugin', 'artefact.myplugin')
* weight: Where in the menu the item should be inserted. Larger number are to the right.
*
* Used by main_nav()
*/
function find_menu_children(&$menu, $path) {
global $SELECTEDSUBNAV;
$result = array();
if (!$menu) {
return array();
}
foreach ($menu as $key => $item) {
$item['selected'] = defined('MENUITEM')
&& ($item['path'] == MENUITEM
|| ($item['path'] . '/' == substr(MENUITEM, 0, strlen($item['path'])+1))
|| (!empty($item['parent']) && $item['parent'] == MENUITEM));
if (
($path == '' && $item['path'] == '') ||
($item['path'] != '' && substr($item['path'], 0, strlen($path)) == $path && !preg_match('%/%', substr($item['path'], strlen($path) + 1)))) {
$result[] = $item;
unset($menu[$key]);
}
}
if ($menu) {
foreach ($result as &$item) {
$item['submenu'] = find_menu_children($menu, $item['path']);
if ($item['selected']) {
$SELECTEDSUBNAV = $item['submenu'];
}
}
}
uasort($result, 'menu_sort_items');
return $result;
}
/**
* Comparison function for sorting menu items
*/
function menu_sort_items(&$a, &$b) {
!isset($a['weight']) && $a['weight'] = 0;
!isset($b['weight']) && $b['weight'] = 0;
return $a['weight'] > $b['weight'];
}
/**
* Site-level sidebar menu (list of links)
* There is no admin files table yet so just get the urls.
* @return $menu a data structure containing the site menu
*/
function site_menu() {
global $USER;
$menu = array();
if ($menuitems = get_records_array('site_menu','public',(int) !$USER->is_logged_in(),'displayorder')) {
foreach ($menuitems as $i) {
if ($i->url) {
$safeurl = sanitize_url($i->url);
if ($safeurl != '') {
$menu[] = array('name' => $i->title,
'link' => $safeurl);
}
}
else if ($i->file) {
$menu[] = array('name' => $i->title,
'link' => get_config('wwwroot') . 'artefact/file/download.php?file=' . $i->file);
}
}
}
return $menu;
}
/**
* Returns the list of site content pages
* @return array of names
*/
function site_content_pages() {
return array('about', 'home', 'loggedouthome', 'privacy', 'termsandconditions');
}
function get_site_page_content($pagename) {
global $USER;
$institution = $USER->sitepages_institutionname_by_theme($pagename);
// try to get the content for this institution and if it fails try to get default site information
// first check to see if the db upgrade has been run so the institution column exists
if (get_config('version') >= '2014010801') {
if ($pagedata = get_record('site_content', 'name', $pagename, 'institution', $institution)) {
return $pagedata->content;
}
else if ($defaultpagedata = get_record('site_content', 'name', $pagename, 'institution', 'mahara')) {
return $defaultpagedata->content;
}
return get_string('sitecontentnotfound', 'mahara', get_string($pagename, $institution));
}
else {
if ($pagedata = get_record('site_content', 'name', $pagename)) {
return $pagedata->content;
}
}
return get_string('sitecontentnotfound', 'mahara', get_string($pagename));
}
/**
* Redirects the browser to a new location. The path to redirect to can take
* two forms:
*
* - http[something]: will redirect the user to that exact URL
* - /[something]: will redirect to WWWROOT/[something]
*
* Any other form is illegal and will cause an error.
*
* @param string $location The location to redirect the user to. Defaults to
* the application home page.
*/
function redirect($location='/') {
$file = $line = null;
if (headers_sent($file, $line)) {
throw new SystemException("Headers already sent when redirect() was called (output started in $file on line $line");
}
if (substr($location, 0, 4) != 'http') {
if (substr($location, 0, 1) != '/') {
throw new SystemException('redirect() should be called with either'
. ' /[something] for local redirects or http[something] for'
. ' absolute redirects');
}
$location = get_config('wwwroot') . substr($location, 1);
}
header('HTTP/1.1 303 See Other');
header('Location:' . $location);
perf_to_log();
exit;
}
/**
* Returns a string, HTML escaped
*
* @param string $text The text to escape
* @return string The text, HTML escaped
*/
function hsc ($text) {
return htmlspecialchars($text, ENT_COMPAT, 'UTF-8');
}
/**
* Builds the pieform for the search field in the page header
*/
function header_search_form() {
$plugin = get_config('searchplugin');
safe_require('search', $plugin);
return call_static_method(
generate_class_name('search', $plugin),
'header_search_form'
);
}
/**
* Returns the name of the current script, WITH the querystring portion.
* this function is necessary because PHP_SELF and REQUEST_URI and SCRIPT_NAME
* return different things depending on a lot of things like your OS, Web
* server, and the way PHP is compiled (ie. as a CGI, module, ISAPI, etc.)
* NOTE: This function returns false if the global variables needed are not set.
*
* @return string
*/
function get_script_path() {
if (!empty($_SERVER['REQUEST_URI'])) {
return $_SERVER['REQUEST_URI'];
} else if (!empty($_SERVER['PHP_SELF'])) {
if (!empty($_SERVER['QUERY_STRING'])) {
return $_SERVER['PHP_SELF'] .'?'. $_SERVER['QUERY_STRING'];
}
return $_SERVER['PHP_SELF'];
} else if (!empty($_SERVER['SCRIPT_NAME'])) {
if (!empty($_SERVER['QUERY_STRING'])) {
return $_SERVER['SCRIPT_NAME'] .'?'. $_SERVER['QUERY_STRING'];
}
return $_SERVER['SCRIPT_NAME'];
} else if (!empty($_SERVER['URL'])) { // May help IIS (not well tested)
if (!empty($_SERVER['QUERY_STRING'])) {
return $_SERVER['URL'] .'?'. $_SERVER['QUERY_STRING'];
}
return $_SERVER['URL'];
}
else {
log_warn('Warning: Could not find any of these web server variables: $REQUEST_URI, $PHP_SELF, $SCRIPT_NAME or $URL');
return false;
}
}
/**
* Get the requested servername in preference to the host in the configured
* wwwroot. Usually the same unless some parts of the site are at subdomains.
*
* @return string
*/
function get_requested_host_name() {
global $CFG;
$hostname = false;
if (false === $hostname && !empty($_SERVER['SERVER_NAME'])) {
$hostname = $_SERVER['SERVER_NAME'];
}
if (false === $hostname && !empty($_ENV['SERVER_NAME'])) {
$hostname = $_ENV['SERVER_NAME'];
}
if (false === $hostname && !empty($_SERVER['HTTP_HOST'])) {
$hostname = $_SERVER['HTTP_HOST'];
}
if (false === $hostname && !empty($_ENV['HTTP_HOST'])) {
$hostname = $_ENV['HTTP_HOST'];
}
if (false === $hostname && !empty($CFG->wwwroot)) {
$url = parse_url($CFG->wwwroot);
if (!empty($url['host'])) {
$hostname = $url['host'];
}
}
if (false === $hostname) {
log_warn('Warning: could not find the name of this server!');
return false;
}
else {
$hostname = strtolower($hostname);
// Because the hostname can be user provided data (from the HTTP request), we
// should whitelist it.
if (!preg_match(
'/^([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])(\\.([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9]))*$/',
$hostname
)
) {
log_warn('Warning: invalid hostname found in get_requested_host_name.');
return false;
}
return $hostname;
}
}
/**
* Like {@link get_script_path()} but returns a full URL
* @see get_script_path()
* @return string
*/
function get_full_script_path() {
global $CFG;
if (!empty($CFG->wwwroot)) {
$url = parse_url($CFG->wwwroot);
}
if (!$hostname = get_requested_host_name()) {
return false;
}
if (!empty($url['port'])) {
$hostname .= ':'.$url['port'];
} else if (!empty($_SERVER['SERVER_PORT'])) {
if ($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) {
$hostname .= ':'.$_SERVER['SERVER_PORT'];
}
}
if (isset($_SERVER['HTTPS'])) {
$protocol = ($_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://';
}
else if (isset($_SERVER['SERVER_PORT'])) { # Apache2 does not export $_SERVER['HTTPS']
$protocol = ($_SERVER['SERVER_PORT'] == '443') ? 'https://' : 'http://';
}
else {
$protocol = 'http://';
}
$url_prefix = $protocol.$hostname;
return $url_prefix . get_script_path();
}
/**
* Like {@link get_script_path()} but returns a URI relative to WWWROOT
* @see get_script_path()
* @return string
*/
function get_relative_script_path() {
$maharadir = get_mahara_install_subdirectory();
// $maharadir always has a trailing '/'
return substr(get_script_path(), strlen($maharadir) - 1);
}
/**
* Get query string from url
*
* Takes in a URL and returns the querystring portion
* or returns $_SERVER['QUERY_STRING']) if set
*
* @param string $url the url which may have a query string attached
* @return string
*/
function get_querystring($url = null) {
if (!empty($url) && $commapos = strpos($url, '?')) {
return substr($url, $commapos + 1);
}
else if (!empty($_SERVER['QUERY_STRING'])) {
return $_SERVER['QUERY_STRING'];
}
else {
return '';
}
}
/**
* Remove query string from url
*
* Takes in a URL and returns it without the querystring portion
*
* @param string $url the url which may have a query string attached
* @return string
*/
function strip_querystring($url) {
if ($commapos = strpos($url, '?')) {
return substr($url, 0, $commapos);
}
else {
return $url;
}
}
function has_page_help() {
$pt = defined('SECTION_PLUGINTYPE') ? SECTION_PLUGINTYPE : null;
$pn = defined('SECTION_PLUGINNAME') ? SECTION_PLUGINNAME : null;
$sp = defined('SECTION_PAGE') ? SECTION_PAGE : null;
if (empty($pt) || ($pt != 'core' && empty($pn))) {
// we can't have a plugin type but no plugin name
return false;
}
if (in_array($pt, plugin_types())) {
$pagehelp = get_config('docroot') . $pt . '/' . $pn . '/lang/en.utf8/help/pages/' . $sp . '.html';
}
else {
$pagehelp = get_config('docroot') . 'lang/en.utf8/help/pages/' . $pn . '/' . $sp . '.html';
}
if (is_readable($pagehelp)) {
return array($sp, get_help_icon($pt, $pn, '', '', $sp));
}
return false;
}
//
// Cleaning/formatting functions
//
/**
* Given some plain text, adds the appropriate HTML to it to make it appear in
* an HTML document with the same formatting
*
* This includes escaping entities, replacing newlines etc. It is not
* particularly intelligent about paragraphs, it just adds
to every
* newline
*
* @param string $text The text to format
* @return string
*/
function format_whitespace($text) {
$text = str_replace("\r\n", "\n", $text);
$text = str_replace("\r", "\n", $text);
$text = hsc($text);
$text = str_replace(' ', ' ', $text);
$text = str_replace(' ', ' ', $text);
$text = str_replace("\n", "
\n", $text);
return $text;
}
/**
* Get the list of custom filters to be used in HTMLPurifier
* @return array
*/
function get_htmlpurifier_custom_filters() {
$customfilters = array();
if (get_config('filters')) {
foreach (unserialize(get_config('filters')) as $filter) {
// These filters are no longer necessary and have been removed
$builtinfilters = array('YouTube', 'TeacherTube', 'SlideShare', 'SciVee', 'GoogleVideo');
if (!in_array($filter->file, $builtinfilters)) {
include_once(get_config('libroot') . 'htmlpurifiercustom/' . $filter->file . '.php');
$classname = 'HTMLPurifier_Filter_' . $filter->file;
if (class_exists($classname)) {
$customfilters[] = new $classname();
}
}
}
}
return $customfilters;
}
/**
* Given raw html (eg typed in by a user), this function cleans it up
* and removes any nasty tags that could mess up pages.
*
* @param string $text The text to be cleaned
* @param boolean $xhtml HTML 4.01 will be used for all of mahara, except very special cases (eg leap2a exports)
* @return string The cleaned up text
*/
function clean_html($text, $xhtml=false) {
require_once('htmlpurifier/HTMLPurifier.auto.php');
$config = HTMLPurifier_Config::createDefault();
$config->set('Cache.SerializerPermissions', get_config('directorypermissions'));
$config->set('Cache.SerializerPath', get_config('dataroot') . 'htmlpurifier');
if (empty($xhtml)) {
$config->set('HTML.Doctype', 'HTML 4.01 Transitional');
}
else {
$config->set('HTML.Doctype', 'XHTML 1.0 Transitional');
}
$config->set('AutoFormat.Linkify', true);
if (get_config('disableexternalresources')) {
$config->set('URI.DisableExternalResources', true);
}
// Permit embedding contents from other sites
$config->set('HTML.SafeEmbed', true);
$config->set('HTML.SafeObject', true);
$config->set('Output.FlashCompat', true);
if ($iframeregexp = get_config('iframeregexp')) {
$config->set('HTML.SafeIframe', true);
$config->set('URI.SafeIframeRegexp', $iframeregexp);
}
// Allow namespaced IDs
// see http://htmlpurifier.org/docs/enduser-id.html
$config->set('Attr.EnableID', true);
$config->set('Attr.IDPrefix', 'user_');
$customfilters = get_htmlpurifier_custom_filters();
if (!empty($customfilters)) {
$config->set('Filter.Custom', $customfilters);
}
// These settings help identify the configuration definition. If the
// definition (the $def object below) is changed (e.g. new method calls
// made on it), the DefinitionRev needs to be increased. See
// http://htmlpurifier.org/live/configdoc/plain.html#HTML.DefinitionID
$config->set('HTML.DefinitionID', 'Mahara customisations to default config');
$config->set('HTML.DefinitionRev', 1);
if ($def = $config->maybeGetRawHTMLDefinition()) {
$def->addAttribute('a', 'target', 'Enum#_blank,_self,_target,_top');
// allow the tags used with image map to be rendered
// see http://htmlpurifier.org/phorum/read.php?3,5046
$def->addAttribute('img', 'usemap', 'CDATA');
// Add map tag
$map = $def->addElement(
'map',
'Block',
'Flow',
'Common',
array(
'name' => 'CDATA',
)
);
$map->excludes = array('map' => true);
// Add area tag
$area = $def->addElement(
'area',
'Block',
'Empty',
'Common',
array(
'name' => 'CDATA',
'alt' => 'Text',
'coords' => 'CDATA',
'accesskey' => 'Character',
'nohref' => new HTMLPurifier_AttrDef_Enum(array('nohref')),
'href' => 'URI',
'shape' => new HTMLPurifier_AttrDef_Enum(array('rect','circle','poly','default')),
'tabindex' => 'Number',
'target' => new HTMLPurifier_AttrDef_Enum(array('_blank','_self','_target','_top'))
)
);
$area->excludes = array('area' => true);
}
$purifier = new HTMLPurifier($config);
return $purifier->purify($text);
}
/**
* Like clean_html(), but for CSS!
*
* Much of the code in this function was taken from the sample code in this post:
* http://stackoverflow.com/questions/3241616/sanitize-user-defined-css-in-php#5209050
*
* @param string $input_css
* @param string $preserve_css, if turns on the CSS comments will be preserved
* @return string The cleaned CSS
*/
function clean_css($input_css, $preserve_css=false) {
require_once('htmlpurifier/HTMLPurifier.auto.php');
require_once('csstidy/class.csstidy.php');
// Create a new configuration object
$config = HTMLPurifier_Config::createDefault();
$config->set('Cache.SerializerPermissions', get_config('directorypermissions'));
$config->set('Cache.SerializerPath', get_config('dataroot') . 'htmlpurifier');
$config->set('Filter.ExtractStyleBlocks', true);
$config->set('Filter.ExtractStyleBlocks.PreserveCSS', $preserve_css);
if (get_config('disableexternalresources')) {
$config->set('URI.DisableExternalResources', true);
}
$customfilters = get_htmlpurifier_custom_filters();
if (!empty($customfilters)) {
$config->set('Filter.Custom', $customfilters);
}
$config->set('HTML.DefinitionID', 'Mahara customisations to default config for CSS');
$config->set('HTML.DefinitionRev', 1);
// Create a new purifier instance
$purifier = new HTMLPurifier($config);
// Wrap our CSS in style tags and pass to purifier.
// we're not actually interested in the html response though
$html = $purifier->purify('');
// The "style" blocks are stored seperately
$output_css = $purifier->context->get('StyleBlocks');
// Get the first style block
if (is_array($output_css) && count($output_css)) {
return $output_css[0];
}
return '';
}
/**
* Given HTML, converts and formats it as text
*
* @param string $html The html to be formatted
* @return string The formatted text
*/
function html2text($html, $fragment=true) {
require_once('htmltotext/htmltotext.php');
if ($fragment) {
$html = '' . $html;
}
$h2t = new HtmltoText($html, get_config('wwwroot'));
return $h2t->text();
}
/**
* Displays purified html on a page with an explanatory message.
*
* @param string $html The purified html.
* @param string $filename The filename to serve the file as
* @param array $params Parameters previously passed to serve_file
*/
function display_cleaned_html($html, $filename, $params) {
$smarty = smarty_core();
$smarty->assign('params', $params);
if ($params['owner']) {
$smarty->assign('htmlremovedmessage', get_string('htmlremovedmessage', 'artefact.file', hsc($filename), profile_url((int) $params['owner']), hsc(display_name($params['owner']))));
}
else {
$smarty->assign('htmlremovedmessage', get_string('htmlremovedmessagenoowner', 'artefact.file', hsc($filename)));
}
$smarty->assign('content', $html);
$smarty->display('cleanedhtml.tpl');
exit;
}
/**
* Takes a string and a length, and ensures that the string is no longer than
* this length, by putting '...' in it somewhere.
*
* It also strips all tags except
and .
*
* This version is appropriate for use on HTML. See str_shorten_text() for use
* on text strings.
*
* @param string $str The string to shorten
* @param int $maxlen The maximum length the new string should be (default 100)
* @param bool $truncate If true, cut the string at the end rather than in the middle (default false)
* @param bool $newlines If false, cut off after the first newline (default true)
* @param bool $usenl2br if false, only do HTML-escapes (default true)
* @return string
*/
function str_shorten_html($str, $maxlen=100, $truncate=false, $newlines=true, $usenl2br=true) {
if (empty($str)) {
return $str;
}
if (!$newlines) {
$nextbreak = strpos($str, '
$str = $str[0] . str_replace('
$maxlen) {
$str = mb_substr($str, 0, $maxlen-3, 'UTF-8') . '...';
}
if (mb_strlen($str, 'UTF-8') > $maxlen) {
$str = mb_substr($str, 0, floor($maxlen / 2) - 1, 'UTF-8') . '...' . mb_substr($str, -(floor($maxlen / 2) - 2), mb_strlen($str, 'UTF-8'), 'UTF-8');
}
}
else {
if ($truncate && strlen($str) > $maxlen) {
$str = substr($str, 0, $maxlen-3) . '...';
}
if (strlen($str) > $maxlen) {
$str = substr($str, 0, floor($maxlen / 2) - 1) . '...' . substr($str, -(floor($maxlen / 2) - 2), strlen($str));
}
}
$str = hsc($str);
if ($usenl2br) {
$str = nl2br($str);
}
// this should be ok, because the string gets checked before going into the database
$str = str_replace('&', '&', $str);
return $str;
}
/**
* Takes a string and a length, and ensures that the string is no longer than
* this length, by putting '...' in it somewhere.
*
* This version is appropriate for use on plain text. See str_shorten_html()
* for use on HTML strings.
*
* @param string $str The string to shorten
* @param int $maxlen The maximum length the new string should be (default 100)
* @param bool $truncate If true, cut the string at the end rather than in the middle (default false)
* @return string
*/
function str_shorten_text($str, $maxlen=100, $truncate=false) {
if (function_exists('mb_substr')) {
if (mb_strlen($str, 'UTF-8') > $maxlen) {
if ($truncate) {
return mb_substr($str, 0, $maxlen - 3, 'UTF-8') . '...';
}
return mb_substr($str, 0, floor($maxlen / 2) - 1, 'UTF-8') . '...' . mb_substr($str, -(floor($maxlen / 2) - 2), mb_strlen($str, 'UTF-8'), 'UTF-8');
}
return $str;
}
if (strlen($str) > $maxlen) {
if ($truncate) {
return substr($str, 0, $maxlen - 3) . '...';
}
return substr($str, 0, floor($maxlen / 2) - 1) . '...' . substr($str, -(floor($maxlen / 2) - 2));
}
return $str;
}
/**
* Builds pagination links for HTML display.
*
* The pagination is quite configurable, but at the same time gives a consistent
* look and feel to all pagination.
*
* This function takes one array that contains the options to configure the
* pagination. Required options include:
*
* - url: The base URL to use for all links (it should not contain special characters)
* - count: The total number of results to paginate for
* - setlimit: toggle variable for enabling/disabling limit dropbox, default value = false
* - limit: How many to show per page
* - offset: At which result to start showing results
*
* Optional options include:
*
* - id: The ID of the div enclosing the pagination
* - class: The class of the div enclosing the pagination
* - offsetname: The name of the offset parameter in the url
* - firsttext: The text to use for the 'first page' link
* - previoustext: The text to use for the 'previous page' link
* - nexttext: The text to use for the 'next page' link
* - lasttext: The text to use for the 'last page' link
* - numbersincludefirstlast: Whether the page numbering should include links
* for the first and last pages
* - numbersincludeprevnext: The number of pagelinks, adjacent the the current page,
* to include per side
* - jumplinks: The maximum number of page jump links to have between first- and current-,
and current- and last page
* - resultcounttextsingular: The text to use for 'result'
* - resultcounttextplural: The text to use for 'results'
* - limittext: The text to use for the limitoption, e.g. "Max items per page" or "Page size"
*
* Optional options to support javascript pagination include:
*
* - datatable: The ID of the table whose TBODY's rows will be replaced with the
* resulting rows
* - jsonscript: The script to make a json request to in order to retrieve
* both the new rows and the new pagination. See js/artefactchooser.json.php
* for an example. Note that the paginator javascript library is NOT
* automatically included just because you call this function, so make sure
* that your smarty() call hooks it in.
*
* @param array $params Options for the pagination
*/
function build_pagination($params) {
$limitoptions = array(1, 10, 20, 50, 100, 500);
// Bail if the required attributes are not present
$required = array('url', 'count', 'limit', 'offset');
foreach ($required as $option) {
if (!isset($params[$option])) {
throw new ParameterException('You must supply option "' . $option . '" to build_pagination');
}
}
if (isset($params['setlimit']) && $params['setlimit']) {
if (!in_array($params['limit'], $limitoptions)) {
$params['limit'] = 10;
}
if (!isset($params['limittext'])) {
$params['limittext'] = get_string('maxitemsperpage1');
}
}
else {
$params['setlimit'] = false;
}
// Work out default values for parameters
if (!isset($params['id'])) {
$params['id'] = substr(md5(microtime()), 0, 4);
}
$params['offsetname'] = (isset($params['offsetname'])) ? $params['offsetname'] : 'offset';
if (isset($params['forceoffset']) && !is_null($params['forceoffset'])) {
$params['offset'] = (int) $params['forceoffset'];
}
else if (!isset($params['offset'])) {
$params['offset'] = param_integer($params['offsetname'], 0);
}
// Correct for odd offsets
if ($params['limit']) {
$params['offset'] -= $params['offset'] % $params['limit'];
}
$params['firsttext'] = (isset($params['firsttext'])) ? $params['firsttext'] : get_string('first');
$params['previoustext'] = (isset($params['previoustext'])) ? $params['previoustext'] : get_string('previous');
$params['nexttext'] = (isset($params['nexttext'])) ? $params['nexttext'] : get_string('next');
$params['lasttext'] = (isset($params['lasttext'])) ? $params['lasttext'] : get_string('last');
$params['resultcounttextsingular'] = (isset($params['resultcounttextsingular'])) ? $params['resultcounttextsingular'] : get_string('result');
$params['resultcounttextplural'] = (isset($params['resultcounttextplural'])) ? $params['resultcounttextplural'] : get_string('results');
if (!isset($params['numbersincludefirstlast'])) {
$params['numbersincludefirstlast'] = true;
}
if (!isset($params['numbersincludeprevnext'])) {
$params['numbersincludeprevnext'] = 1;
}
else {
$params['numbersincludeprevnext'] = (int) $params['numbersincludeprevnext'];
}
if (!isset($params['extradata'])) {
$params['extradata'] = null;
}
// Begin building the output
$output = '
';
return array('html' => $output, 'javascript' => $js);
}
/**
* Used by build_pagination to build individual links. Shouldn't be used
* elsewhere.
*
* @param $class String
* @param $text String
* @param $title String
* @param $disabled Boolean (optional)
* @param $url String
* @param $setlimit Int
* @param $limit Int
* @param $offset Int
* @param $offsetname String (optional)
*/
function build_pagination_pagelink($class, $text, $title, $disabled=false, $url=false, $setlimit=false, $limit=false, $offset=false, $offsetname='offset') {
if ($url) {
$url = (false === strpos($url, '?')) ? $url . '?' : $url . '&';
$url .= "$offsetname=$offset";
if ($setlimit) {
$url .= '&' . "setlimit=$setlimit";
$url .= '&' . "limit=$limit";
}
}
$result = "";
if (!empty($title)) {
$text .= '' . $title . '';
}
if ($disabled) {
$result .= '';
$result .= $text;
$result .= '';
} else {
$result .= '';
$result .= $text;
$result .= '';
}
$result .= '';
return $result;
}
function mahara_http_request($config, $quiet=false) {
$ch = curl_init();
// standard curl_setopt stuff; configs passed to the function can override these
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
if (!ini_get('open_basedir')) {
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
}
curl_setopt_array($ch, $config);
if($proxy_address = get_config('proxyaddress')) {
curl_setopt($ch, CURLOPT_PROXY, $proxy_address);
if($proxy_authmodel = get_config('proxyauthmodel') && $proxy_credentials = get_config('proxyauthcredentials')) {
// todo: actually do something with $proxy_authmodel
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxy_credentials);
}
}
if (strpos($config[CURLOPT_URL], 'https://') === 0) {
if ($cainfo = get_config('cacertinfo')) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, $cainfo);
}
}
$result = new StdClass();
$result->data = curl_exec($ch);
$result->info = curl_getinfo($ch);
$result->error = curl_error($ch);
$result->errno = curl_errno($ch);
if ($result->errno) {
if ($quiet) {
// When doing something unimportant like fetching rss feeds, some errors should not pollute the logs.
$dontcare = array(
CURLE_COULDNT_RESOLVE_HOST, CURLE_COULDNT_CONNECT, CURLE_PARTIAL_FILE, CURLE_OPERATION_TIMEOUTED,
CURLE_GOT_NOTHING,
);
$quiet = in_array($result->errno, $dontcare);
}
if (!$quiet) {
log_warn('Curl error: ' . $result->errno . ': ' . $result->error);
}
}
curl_close($ch);
return $result;
}
/**
* Fetch the true full url from a shorthand url by getting
* the location from the redirected header information.
*
* @param string $url The shorthand url eg https://goo.gl/maps/pZTiA
* @param bool $quiet To record errors in the logs
*
* @return object $result Contains the short url, full url, the headers, and any errors
*/
function mahara_shorturl_request($url, $quiet=false) {
$ch = curl_init($url);
// standard curl_setopt stuff; configs passed to the function can override these
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_MAXREDIRS, 1);
$result = new StdClass();
$result->shorturl = $url;
$result->data = curl_exec($ch);
$result->error = curl_error($ch);
$result->errno = curl_errno($ch);
if ($result->errno) {
if ($quiet) {
// When doing something unimportant like fetching rss feeds, some errors should not pollute the logs.
$dontcare = array(
CURLE_COULDNT_RESOLVE_HOST, CURLE_COULDNT_CONNECT, CURLE_PARTIAL_FILE, CURLE_OPERATION_TIMEOUTED,
CURLE_GOT_NOTHING,
);
$quiet = in_array($result->errno, $dontcare);
}
if (!$quiet) {
log_warn('Curl error: ' . $result->errno . ': ' . $result->error);
}
}
curl_close($ch);
$fields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', $result->data)); // Parse information
$result->fullurl = false;
foreach ($fields as $field) {
if (strpos($field, 'Location') !== false) {
$result->fullurl = str_replace('Location: ', '', $field);
}
}
return $result;
}
/**
* Returns a language select form
*
* @return string HTML of language select form
*/
function language_select_form() {
global $SESSION;
$languageform = '';
$languages = get_languages();
if (count($languages) > 1) {
$languages = array_merge(array('default' => get_string('sitedefault', 'admin') . ' (' .
get_string_from_language(get_config('lang'), 'thislanguage') . ')'), $languages);
require_once('pieforms/pieform.php');
$languageform = pieform(array(
'name' => 'languageselect',
'renderer' => 'div',
'class' => 'form-inline with-label-widthauto',
'validate' => false,
'presubmitcallback' => '',
'elements' => array(
'inputgroup' => array(
'type' => 'fieldset',
'class' => 'input-group',
'elements' => array(
'lang' => array(
'type' => 'select',
'title' => get_string('language') . ':',
'hiddenlabel' => true,
'options' => $languages,
'defaultvalue' => $SESSION->get('lang') ? $SESSION->get('lang') : 'default',
),
'changelang' => array(
'type' => 'button',
'usebuttontag' => true,
'class' => 'btn-default input-group-btn',
'value' => get_string('change'),
)
)
)
),
));
}
return $languageform;
}
/**
* Sanitises URIs provided before displaying them to the world, as well as checking they are of
* appropriate protocols and complete.
*
* @return string Either an empty string if supplied URI fails tests, or the supplied URI verbatim
*/
function sanitize_url($url) {
$parsedurl = parse_url($url);
if (empty($parsedurl['scheme'])) {
if (!empty($parsedurl['path'])) {
$url = get_config('wwwroot') . ltrim($url, '/');
$parsedurl = parse_url($url);
}
else {
return '';
}
}
// Make sure the URL starts with a valid protocol (or "//", indicating that it's protocol-relative)
if (
!(
in_array($parsedurl['scheme'], array('https', 'http', 'ftp', 'mailto'))
|| preg_match('#^//[a-zA-Z0-9]#', $url) === 1
)
) {
return '';
}
if (!filter_var($url, FILTER_VALIDATE_URL)) {
return '';
}
return $url;
}
/**
* Sanitises header text per rfc5322
*
* @return string A string with undesired characters filtered out
*/
function clean_email_headers($headertext) {
$decoloned = str_replace(':', '', $headertext);
$filtered = filter_var($decoloned, FILTER_SANITIZE_STRING, array(FILTER_FLAG_STRIP_LOW, FILTER_FLAG_STRIP_HIGH));
return substr($filtered, 0, 100);
}
function favicon_display_url($host) {
$url = sprintf(get_config('favicondisplay'), $host);
if (is_https()) {
$url = str_replace('http://', 'https://', $url);
}
return $url;
}
/**
* Given an arbitrary string, generate a string containing only the allowed
* characters for use in a clean url.
*
* @param string $dirty string containing invalid or undesirable url characters
* @param mixed $default an integer id or clean string to use as the default
* @param integer $minlength
* @param integer $maxlength
*
* @return string A string of the specified length containing only valid characters
*/
function generate_urlid($dirty, $default, $minlength=3, $maxlength=100) {
$charset = get_config('cleanurlcharset');
if ($charset != 'ASCII' || preg_match('/[^\x00-\x7F]/', $dirty)) {
$dirty = iconv('UTF-8', $charset . '//TRANSLIT', $dirty);
}
$dirty = preg_replace(get_config('cleanurlinvalidcharacters'), '-', $dirty);
$s = substr(strtolower(trim($dirty, '-')), 0, $maxlength);
// If the string is too short, use the default, padding with zeros if necessary
$length = strlen($s);
if ($length < $minlength) {
if (is_numeric($default)) {
$format = '%0' . $minlength . 'd';
$default = sprintf($format, (int) $default);
}
if ($length > 0) {
$default .= '-' . $s;
}
$s = $default;
}
return $s;
}
/**
* Generate a valid name for the institution.name column, based on the specified display name
*
* @param string $displayname
* @return string
*/
function generate_institution_name($displayname) {
// iconv can crash on strings that are too long, so truncate before converting
$basename = mb_substr($displayname, 0, 255);
$basename = iconv('UTF-8', 'ASCII//TRANSLIT', $displayname);
$basename = strtolower($basename);
$basename = preg_replace('/[^a-z]/', '', $basename);
if (strlen($basename) < 2) {
$basename = 'inst' . $basename;
}
else {
$basename = substr($basename, 0, 255);
}
// Make sure the name is unique. If it is not, add a suffix and see if
// that makes it unique
$finalname = $basename;
$suffix = 'a';
while (record_exists('institution', 'name', $finalname)) {
// Add the suffix but make sure the name length doesn't go over 255
$finalname = substr($basename, 0, 255 - strlen($suffix)) . $suffix;
// Will iterate a-z, aa-az, ba-bz, etc.
// See: http://php.net/manual/en/language.operators.increment.php
$suffix++;
}
return $finalname;
}
/**
* Sorts an array by one of the value fields
*
* @param array $data an array of arrays
* @param string $sort a key field value of second tier array
* @param string $direction the direction of the sort
*/
function sorttablebycolumn(&$data, $sort, $direction) {
global $sortvalue;
$sortvalue = $sort;
if ($direction == 'desc') {
usort($data, 'sorttablearraydesc'); }
else {
usort($data, 'sorttablearrayasc');
}
}
/**
* Compare function for sorttablebycolumn()
* Sorts ascending.
*/
function sorttablearrayasc($a, $b) {
global $sortvalue;
if (is_string($a[$sortvalue])) {
return strcmp(strtolower($a[$sortvalue]), strtolower($b[$sortvalue]));
}
return ($a[$sortvalue] < $b[$sortvalue]) ? -1 : 1;
}
/**
* Compare function for sorttablebycolumn()
* Sorts descending
*/
function sorttablearraydesc($a, $b) {
global $sortvalue;
if (is_string($a[$sortvalue])) {
return strcmp(strtolower($b[$sortvalue]), strtolower($a[$sortvalue]));
}
return ($b[$sortvalue] < $a[$sortvalue]) ? -1 : 1;
}
/**
* Add version number to url
* This allows auto refreshing of cache when upgrading
* or updating Mahara to different version
*/
function append_version_number($urls) {
if (is_array($urls)) {
$formattedurls = array();
foreach ($urls as $url) {
if (preg_match('/\?/',$url)) {
$url .= '&v=' . get_config('cacheversion');
}
else {
$url .= '?v=' . get_config('cacheversion');
}
$formattedurls[] = $url;
}
return $formattedurls;
}
if (preg_match('/\?/',$urls)) {
$urls .= '&v=' . get_config('cacheversion');
}
else {
$urls .= '?v=' . get_config('cacheversion');
}
return $urls;
}
/**
* Escape a string so that it's suitable to be used as a CSS quote-enclosed string
* If it's single-quoted, preface single-quotes with a backslash. If it's double-quoted,
* preface double-quotes with a backslash. Preface non-escaping backslashes with a
* backslash. Remove newlines.
* @param string $string The string to escape
* @param bool $singlequote True to escape for single quotes, False to escape for double
* @return string
*/
function escape_css_string($string, $singlequote=true) {
if ($singlequote) {
$delim = "'";
}
else {
$delim = '"';
}
return str_replace(
array('\\', "\n", $delim),
array('\\\\', '', "\\$delim"),
$string
);
}
/**
* Indicates whether a particular user can use skins on their pages or not. This is in
* lib/web.php instead of lib/skin.php so that we can use it while generating the main nav.
* @param int $userid The Id of the user to check. Null checks the current user.
* @param bool $managesiteskin = true if admins try to manage the site skin
* @param bool $issiteview = true if admins try to use skins for site views
* @return bool
*/
function can_use_skins($userid = null, $managesiteskin=false, $issiteview=false) {
global $USER;
if (!get_config('skins')) {
return false;
}
// Site Admins can access site skin
if ($USER->get('admin') && ($managesiteskin || $issiteview)) {
return true;
}
// A user can belong to multiple institutions. If any of their institutions allow it, then
// let them use skins!
$results = get_configs_user_institutions('skins', $userid);
foreach ($results as $r) {
if ($r) {
return true;
}
}
return false;
}
/**
* Display image icon based on name
*
* @param string $type Type of icon image to show
* @param string $id Optional id to add to the image
*
* @return string An
tag of the icon we want
*/
function display_icon($type, $id = false) {
global $THEME;
switch ($type) {
case 'on':
case 'yes':
case 'success':
case 'true':
case 'enabled':
$image = 'icon icon-lg icon-check text-success';
break;
case 'off':
case 'no':
case 'fail':
case 'false':
case 'disabled':
$image = 'icon icon-lg icon-times text-danger';
break;
}
$html = '