ÿØÿà JFIF    ÿÛ „  ( %!1"%)+...383-7(-.+  -%%--------+------------/----------------------------ÿÀ  ¶" ÿÄ     ÿÄ @    !1AQaq‘¡"±ÁÑð2’BRráS‚ñ3b¢CT²Ò #cÿÄ    ÿÄ '   1!AQ2a"‘±#ÿÚ   ? ò(/p‘—–¢·,M|¯G»R£üešT. ôŸEoCFñ‡ 4ÔkåóxR|µÁ¨ÓDà!Ç´µ˜‡p ÍQ‹§!þž^õWsŒy  åÁ§$á«%ºq˜™JyyË0y«^Ϗ -3ÃÏËÈ£Æ\P’ä„s&•‹Üs üô'àWt¹pñCp$bÚF`·7.^)¾!)ÒÙ˜–ÅÏš^h¾ø³·ìe±ŒaeÖ—Í,e=B}Jéߦ$$½—šÙÜCC¯¶è8β–Åkèwx LÉngT±æ¹£Ócœ¿Í/©Éÿ ‰ÚCÒ­mq;Tt¶–}0"zÖPcd1š­¤tˆ„ÐÓâqú[™öUCŠ2޿د­É(¸ßúçšmW,Ò ºf‹Ån™ÄLêÁ8üÁkÁ€L¥ÍuJ1œôrÂSŒÓöt!7EUíïb)AËi¬â-ÙHk8òÁiXYwÅ)O^"ÇØriÛô{»wRUKÙÏÚlÓ¬€‚’שT ] ªb—ÊîKC^×M“xùäñz¬zJ× {4[¹M'IÆeH1LCWÕ]œûº WDæà°OÅ‚¹c²ÞuA–rL`HšpCez‡V’— Ž‚Ë„–ñ­'µR0ÕÖ=À:±G»C\nÆÉ5*¢ †3šhQ4ýÒi$Õ1"Ü]¢p-q3zcQ$ªö¨¥æf›‘»´ÝÚHá„e²JÇ–iÊ:·à¬Øc5Åk»Laª*wi [0Ówk ¦a¦0Õ²ÅÅ‚T¸’³q:Æ<¹ú Ò˜Æ}2VE•Ѐp¡Ô3Úº …h³^LJºçì¥Ánó|˜ÖˆÎˆ+« ¦dø‘Mº–d\ªDðÛ„Ì×LÝ——Ð9Ç|•FèçVm™¨€™3õS–9Äå¢<̉Ìm¢±`·º˜&Z²ž Ë®D«¶»6™‰©­HÈ Àá«h­i³04æ’hxœi3ï¨(ÓL·†‹¶ËpŒ ƒÜÒ? :õdsÀ –3æÓ·Üjâ¬9—]8n¼&]I F£¼…ì–—Œ0v°LǐÅfÛ2TÖ’aµ˜N@ÖBSÏ^à´4-±°b×nÈÈœÆD=KdŒø…ÄÈK,›ÖR§fjü$^ÔÎ!„6^ s:Üun\ôkCÞò÷<—Lúl Í›G¹ÀPá¼Nc¡šÒ…ÙWͳœ±vÊáЄ×9‹P‰cEØ‘™›µŸP<×g1 º©Ø¬wiÁ^l5× I/';Ë+´Z‡ÓÄFÕp[Èð’ HÄ ó 9¬Dl4“é±Ï”V=^Hð;žLädÉa‚°Ë,#/Ž~²BÔÛ QãñQtIeórVB,ÏÂf‹4#Μc‹É3ZIÖ Œ¢¥·üxa‡Ãçè„jŠ[5 Ä!U?,3žÎ×…ðdÓ÷háŠA‰ìÄ4÷ÃÜZÃE{‰®+W\ZÍE[‰»µk»MÝ­`¢©†˜ÃV‹-f¢¡†¢a«eŠ%«Y¨©q%jâd,Ôq`) ¤¦…šˆ ¦E>0Ùb²t–Ÿ  ÷jsςҒKÈcø(é›;k(’#ôŒQ ™C> õ³M9óºÆµ¤çâ;uÀ)5>RÔ¸fÓ~Ȧ—’-$fe«"FâUˆÊwµPÏu w+"åÉó¨6s™Û9(À¨ù©hE°½†n`m~“@©›p!Vkhµ Á1šbEqqÊ@ºèl›2 –Yã%‘‚hÛ{a¶‡ÅÞM²¬çL34®Çl]®‹ŽØŒm'RÜe35æöˆ­Á­ cP9šeÁköo´L³Ì=p8]”‡B¶,šº|ɏdzXˆØk*ÇÚ{#ñ‰pã(€¶‡9ý'šÜ³½¯kƒ†Â’ëSOƒ•Å®H6+a¢µˆ‹Y¨b˜b+XˆÖ!°u!¢"µˆˆn2ˆ Å0Ä`Å Ô®c(ÓÜGº•Ä»Œ âWî%q.áÐÄ÷î%umÍ£+ÜQ,Vn¦-GphU¸¢X­&,Gt ·K¢ÅÅ·¥RÄÊÉbKn N­R2g$VµÕó Qr#–ÓZUÏð0ÎtÙÀœz ëöo“Îk¯n„T°"SÞ+³/…€½"ižãO%Í%&Δâ‘ËØ´IˆÓ°Ë‰ÞM3.™yçÁzit›`4C`k¢¼á!álÄï sÂ[×!¤l¾æo"ƒIÔ'@ªu)3›ô®“@Z à¾] üœ'‡4¸PÞkÁ-qÄH‰ÓÍBd´ÿ —¹°ÄA&ÊUC„öz‚‚RæŠtf¬>˜ÑidšEçÑL÷áý¡V±h§­c¿¥¨ƒ@g¼…Ýö^ÞËc.ž„æ“I[ ª+·zÐÒÚ,½Ð»¶€C›7jk$๖€Ž¾ÅÙpp¶ÍþéΤ ½ØÎŒq ñpæžÅ¥#Øâ49ÃÂK^MYV“,¶Éz_òæ:…;Õ«¦I3âJ£¤û5$7Èxün\â]Êe¯(Ÿ&Ž‹¶2<6Ćf× æ¢ƱqWı[(ÙÂŽç‚T7¨@ÈÉÍß‚ïÙ"&3TYlGށ†)†#5ŠA©^T2ÆÁ†)©†©†¤yGXÁ†©"†)©¼ÅV WS†#©]R–r‹q5ÕbâWþBh¯u+ªÅÄ×ü„nÑ^êkªÁj‰jeœWˆÕÕ`µDµ2Ì+Ä µDµµ5Ô{¤Þ0RF’H÷AÛ<ÊÁ§ ƈæ0Ñ£ê4 öÚµ[¬/1²€â<-¬šö²r×0o×w ´xÐÒË„ g01¬„åEM蛇Ã\6µE›‘fÙO k÷CºnÓ1`iîÒ² áÂ!ÑLÄÿ ³¬\õ*:M=Ç»c‹2[‰ØsÕLò\ŒK L^™üÄN\¶#» Ç\……ßïIœÉ$¸ÎñÍ®ÔHÇ Ûí/´>Li”„†g^$ 7NÍÑÑ2M2ªNg=k½Ð}Ÿl6‡ —JWˆ”ÞéT·+µ¦üÂFè¢Vs6ýÆ4»2+2IÝ9ô9®ÇGÙÇ1+Ä8;*Õ§ž½D*îÑWÚçá3Ma¤·ˆ¥t}š²Ü…Q+Æüµ8HíS”üxGéÁˆ¦Ël„éÈ 5 µÄƒ6äÜ(kIš¯S†fÖ&¸®×v|Äyˆ*禌Éù@7-®Ä[]ÎÖ¿ê`º…=:…žJVnݳvðÖKE¼‚ »mà ÷f®:Ë ™–4rð¡4` ܹçž~‹C=œ…¾Ïj|VDtK.ƒ"9 Ï ­–éXá³6WÒïIL-Ї Ç home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/competency/classes/url.php000064400000014112152266552560024014 0ustar00. /** * URL manager. * * @package core_competency * @copyright 2016 Frédéric Massart - FMCorz.net * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace core_competency; defined('MOODLE_INTERNAL') || die(); use moodle_url; /** * URL manager class. * * This class has to be used to get the URL to a resource, this allows for different * alternate frontends to be used without resorting to core hacks. Note that you * do not have to use this when you are navigating between pages of your own plugin. * * To set another resolver, set the following config value in config.php: * $CFG->core_competency_url_resolver = 'your_plugin\\your_url_resolver_class'; * * Your URL resolver should implement the same methods as the ones listed in * this class (except for {{@link self::get()}}) but not statically. * * /!\ Note, resolvers MUST NEVER assume that the resource, or the resources * represented by the arguments, still exist. * * @package core_competency * @copyright 2016 Frédéric Massart - FMCorz.net * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class url { /** @var url_resolver The URL resolver instance.*/ protected static $resolver; /** * Defer to the resolver. * * @param string $resource The resource type. * @param array $args The arguments. * @return mixed */ protected static function get($resource, $args) { global $CFG; if (!isset(static::$resolver)) { $klass = !empty($CFG->core_competency_url_resolver) ? $CFG->core_competency_url_resolver : 'tool_lp\\url_resolver'; static::$resolver = new $klass(); } if (!method_exists(static::$resolver, $resource)) { debugging("URL for '$resource' not implemented.", DEBUG_DEVELOPER); return new moodle_url('/'); } return call_user_func_array([static::$resolver, $resource], $args); } /** * The URL where the competency can be found. * * @param int $competencyid The competency ID. * @param int $pagecontextid The ID of the context we are in. * @return moodle_url */ public static function competency($competencyid, $pagecontextid) { return static::get(__FUNCTION__, func_get_args()); } /** * The URL where the framework can be found. * * @param int $frameworkid The framework ID. * @param int $pagecontextid The ID of the context we are in. * @return moodle_url */ public static function framework($frameworkid, $pagecontextid) { return static::get(__FUNCTION__, func_get_args()); } /** * The URL where the frameworks can be found. * * @param int $pagecontextid The ID of the context that we are browsing. * @return moodle_url */ public static function frameworks($pagecontextid) { return static::get(__FUNCTION__, func_get_args()); } /** * The URL where the plan can be found. * * @param int $planid The plan ID. * @return moodle_url */ public static function plan($planid) { return static::get(__FUNCTION__, func_get_args()); } /** * The URL where the plans of a user can be found. * * @param int $userid The user ID. * @return moodle_url */ public static function plans($userid) { return static::get(__FUNCTION__, func_get_args()); } /** * The URL where the template can be found. * * @param int $templateid The template ID. * @param int $pagecontextid The ID of the context we are in. * @return moodle_url */ public static function template($templateid, $pagecontextid) { return static::get(__FUNCTION__, func_get_args()); } /** * The URL where the templates can be found. * * @param int $pagecontextid The ID of the context that we are browsing. * @return moodle_url */ public function templates($pagecontextid) { return static::get(__FUNCTION__, func_get_args()); } /** * The URL where the user competency can be found. * * @param int $usercompetencyid The user competency ID * @return moodle_url */ public static function user_competency($usercompetencyid) { return static::get(__FUNCTION__, func_get_args()); } /** * The URL where the user competency can be found in the context of a course. * * @param int $userid The user ID * @param int $competencyid The competency ID. * @param int $courseid The course ID. * @return moodle_url */ public static function user_competency_in_course($userid, $competencyid, $courseid) { return static::get(__FUNCTION__, func_get_args()); } /** * The URL where the user competency can be found in the context of a plan. * * @param int $userid The user ID * @param int $competencyid The competency ID. * @param int $planid The plan ID. * @return moodle_url */ public static function user_competency_in_plan($userid, $competencyid, $planid) { return static::get(__FUNCTION__, func_get_args()); } /** * The URL where the user evidence (of prior learning) can be found. * * @param int $userevidenceid The user evidence ID * @return moodle_url */ public static function user_evidence($userevidenceid) { return static::get(__FUNCTION__, func_get_args()); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/url/lang/en/url.php000064400000015761152267154370023126 0ustar00. /** * Strings for component 'url', language 'en', branch 'MOODLE_20_STABLE' * * @package mod_url * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ $string['allowvariables'] = 'Allow URL variables'; $string['allowvariables_desc'] = 'Allow variables to be added to URLs. Variables enable you to pass internal information, such as the user\'s name, as part of the URL. Be aware of potential privacy risks when using this feature.'; $string['clicktoopen'] = 'Click on {$a} to open the resource.'; $string['configdisplayoptions'] = 'Select all options that should be available, existing settings are not modified. Hold CTRL key to select multiple fields.'; $string['configframesize'] = 'When a web page or an uploaded file is displayed within a frame, this value is the height (in pixels) of the top frame (which contains the navigation).'; $string['configrolesinparams'] = 'Should customised role names (from the course settings) be available as variables for URL parameters?'; $string['configsecretphrase'] = 'This secret phrase is used to produce encrypted code value that can be sent to some servers as a parameter. The encrypted code is produced by an md5 value of the current user IP address concatenated with your secret phrase. ie code = md5(IP.secretphrase). Please note that this is not reliable because IP address may change and is often shared by different computers.'; $string['contentheader'] = 'Content'; $string['createurl'] = 'Create a URL'; $string['displayoptions'] = 'Available display options'; $string['displayselect'] = 'Display'; $string['displayselect_help'] = 'This setting, together with the URL file type and whether the browser allows embedding, determines how the URL is displayed. Options may include: * Automatic - The best display option for the URL is selected automatically * Embed - The URL is displayed within the page below the navigation bar together with the URL description and any blocks * Open - Only the URL is displayed in the browser window * In pop-up - The URL is displayed in a new browser window without menus or an address bar * In frame - The URL is displayed within a frame below the navigation bar and URL description * New window - The URL is displayed in a new browser window with menus and an address bar'; $string['displayselectexplain'] = 'Choose display type, unfortunately not all types are suitable for all URLs.'; $string['externalurl'] = 'External URL'; $string['framesize'] = 'Frame height'; $string['invalidstoredurl'] = 'Cannot display this resource, URL is invalid.'; $string['chooseavariable'] = 'Choose a variable...'; $string['indicator:cognitivedepth'] = 'URL cognitive'; $string['indicator:cognitivedepth_help'] = 'This indicator is based on the cognitive depth reached by the student in a URL resource.'; $string['indicator:cognitivedepthdef'] = 'URL cognitive'; $string['indicator:cognitivedepthdef_help'] = 'The participant has reached this percentage of the cognitive engagement offered by the URL resources during this analysis interval (Levels = No view, View)'; $string['indicator:cognitivedepthdef_link'] = 'Learning_analytics_indicators#Cognitive_depth'; $string['indicator:socialbreadth'] = 'URL social'; $string['indicator:socialbreadth_help'] = 'This indicator is based on the social breadth reached by the student in a URL resource.'; $string['indicator:socialbreadthdef'] = 'URL social'; $string['indicator:socialbreadthdef_help'] = 'The participant has reached this percentage of the social engagement offered by the URL resources during this analysis interval (Levels = No participation, Participant alone)'; $string['indicator:socialbreadthdef_link'] = 'Learning_analytics_indicators#Social_breadth'; $string['invalidurl'] = 'Entered URL is invalid'; $string['modulename'] = 'URL'; $string['modulename_help'] = 'The URL module enables a teacher to provide a web link as a course resource. Anything that is freely available online, such as documents or images, can be linked to; the URL doesn’t have to be the home page of a website. The URL of a particular web page may be copied and pasted or a teacher can use the file picker and choose a link from a repository such as Flickr, YouTube or Wikimedia (depending upon which repositories are enabled for the site). There are a number of display options for the URL, such as embedded or opening in a new window and advanced options for passing information, such as a student\'s name, to the URL if required. Note that URLs can also be added to any other resource or activity type through the text editor.'; $string['modulename_link'] = 'mod/url/view'; $string['modulenameplural'] = 'URLs'; $string['name'] = 'Name'; $string['name_help'] = 'This will serve as the link text for the URL. Enter a meaningful text that concisely describes the URL\'s purpose. Avoid using the word "link". This will help screen reader users as screen readers announce links (e.g. "Moodle.org, link") so there\'s no need to include the word "link" in the name field.'; $string['page-mod-url-x'] = 'Any URL module page'; $string['parameterinfo'] = '&parameter=variable'; $string['parametersheader'] = 'URL variables'; $string['parametersheader_help'] = 'This section allows you to pass internal information as part of the URL. This is useful if the URL is an interactive web page that takes parameters, and you want to pass something like the name of the current user, for example. Enter the name of the URL\'s parameter in the text box then select the corresponding site variable.'; $string['pluginadministration'] = 'URL module administration'; $string['pluginname'] = 'URL'; $string['popupheight'] = 'Pop-up height (in pixels)'; $string['popupheightexplain'] = 'Specifies default height of popup windows.'; $string['popupwidth'] = 'Pop-up width (in pixels)'; $string['popupwidthexplain'] = 'Specifies default width of popup windows.'; $string['printintro'] = 'Display URL description'; $string['printintroexplain'] = 'Display URL description below content? Some display types may not display description even if enabled.'; $string['privacy:metadata'] = 'The URL resource plugin does not store any personal data.'; $string['rolesinparams'] = 'Role names as URL variables'; $string['search:activity'] = 'URL'; $string['serverurl'] = 'Server URL'; $string['url:addinstance'] = 'Add a new URL resource'; $string['url:view'] = 'View URL'; home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/lib/form/url.php000064400000016011152267671770021730 0ustar00. /** * url type form element * * Contains HTML class for a url type element * * @package core_form * @copyright 2009 Dongsheng Cai * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require_once("HTML/QuickForm/text.php"); require_once('templatable_form_element.php'); /** * url type form element * * HTML class for a url type element * @package core_form * @category form * @copyright 2009 Dongsheng Cai * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class MoodleQuickForm_url extends HTML_QuickForm_text implements templatable { use templatable_form_element { export_for_template as export_for_template_base; } /** @var string html for help button, if empty then no help */ var $_helpbutton=''; /** @var bool if true label will be hidden */ var $_hiddenLabel=false; /** @var string the unique id of the filepicker, if enabled.*/ protected $filepickeruniqueid; /** @var array data which need to be posted. */ protected $_options; /** * Constructor * * @param string $elementName Element name * @param mixed $elementLabel Label(s) for an element * @param mixed $attributes Either a typical HTML attribute string or an associative array. * @param array $options data which need to be posted. */ public function __construct($elementName=null, $elementLabel=null, $attributes=null, $options=null) { global $CFG; require_once("$CFG->dirroot/repository/lib.php"); $options = (array)$options; foreach ($options as $name=>$value) { $this->_options[$name] = $value; } if (!isset($this->_options['usefilepicker'])) { $this->_options['usefilepicker'] = true; } parent::__construct($elementName, $elementLabel, $attributes); $this->_type = 'url'; } /** * Old syntax of class constructor. Deprecated in PHP7. * * @deprecated since Moodle 3.1 */ public function MoodleQuickForm_url($elementName=null, $elementLabel=null, $attributes=null, $options=null) { debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER); self::__construct($elementName, $elementLabel, $attributes, $options); } /** * Sets label to be hidden * * @param bool $hiddenLabel sets if label should be hidden */ function setHiddenLabel($hiddenLabel){ $this->_hiddenLabel = $hiddenLabel; } /** * Returns HTML for this form element. * * @return string */ function toHtml(){ $id = $this->_attributes['id']; $elname = $this->_attributes['name']; // Add the class at the last minute. if ($this->get_force_ltr()) { if (!isset($this->_attributes['class'])) { $this->_attributes['class'] = 'text-ltr'; } else { $this->_attributes['class'] .= ' text-ltr'; } } if ($this->_hiddenLabel) { $this->_generateId(); $str = ''.parent::toHtml(); } else { $str = parent::toHtml(); } if (empty($this->_options['usefilepicker'])) { return $str; } // Print out file picker. $str .= $this->getFilePickerHTML(); $str = '
' . $str . '
'; return $str; } public function getFilePickerHTML() { global $PAGE, $OUTPUT; $str = ''; $clientid = $this->get_filepicker_unique_id(); $args = new stdClass(); $args->accepted_types = '*'; $args->return_types = FILE_EXTERNAL; $args->context = $PAGE->context; $args->client_id = $clientid; $args->env = 'url'; $fp = new file_picker($args); $options = $fp->options; if (count($options->repositories) > 0) { $straddlink = get_string('choosealink', 'repository'); $str .= << $straddlink EOD; } // print out file picker $str .= $OUTPUT->render($fp); $module = array('name'=>'form_url', 'fullpath'=>'/lib/form/url.js', 'requires'=>array('core_filepicker')); $PAGE->requires->js_init_call('M.form_url.init', array($options), true, $module); return $str; } /** * get html for help button * * @return string html for help button */ function getHelpButton(){ return $this->_helpbutton; } /** * Slightly different container template when frozen. Don't want to use a label tag * with a for attribute in that case for the element label but instead use a div. * Templates are defined in renderer constructor. * * @return string */ function getElementTemplateType(){ if ($this->_flagFrozen){ return 'static'; } else { return 'default'; } } public function export_for_template(renderer_base $output) { $context = $this->export_for_template_base($output); $context['filepickerhtml'] = !empty($this->_options['usefilepicker']) ? $this->getFilePickerHTML() : ''; // This will conditionally wrap the element in a div which can be accessed in the DOM using the unique id, // and allows the filepicker callback to find its respective url field, if multiple URLs are used. if ($this->_options['usefilepicker']) { $context['filepickerclientid'] = $this->get_filepicker_unique_id(); } return $context; } /** * Get force LTR option. * * @return bool */ public function get_force_ltr() { return true; } /** * Returns the unique id of the file picker associated with this url element, setting it in the process if not set. * * @return string the unique id of the file picker. */ protected function get_filepicker_unique_id(): string { if (empty($this->filepickeruniqueid)) { $this->filepickeruniqueid = uniqid(); } return $this->filepickeruniqueid; } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/lib/classes/url.php000064400000100065152267723460022417 0ustar00. namespace core; use core\context\user as context_user; use core\exception\coding_exception; use core\exception\moodle_exception; use Psr\Http\Message\UriInterface; /** * Class for creating and manipulating urls. * * It can be used in moodle pages where config.php has been included without any further includes. * * It is useful for manipulating urls with long lists of params. * One situation where it will be useful is a page which links to itself to perform various actions * and / or to process form data. A url object: * can be created for a page to refer to itself with all the proper get params being passed from page call to * page call and methods can be used to output a url including all the params, optionally adding and overriding * params and can also be used to * - output the url without any get params * - and output the params as hidden fields to be output within a form * * @copyright 2007 jamiesensei * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @package core */ class url { /** * Scheme, ex.: http, https * @var string */ protected $scheme = ''; /** * Hostname. * @var string */ protected $host = ''; /** * Port number, empty means default 80 or 443 in case of http. * @var int */ protected $port = ''; /** * Username for http auth. * @var string */ protected $user = ''; /** * Password for http auth. * @var string */ protected $pass = ''; /** * Script path. * @var string */ protected $path = ''; /** * Optional slash argument value. * @var string */ protected $slashargument = ''; /** * Anchor, may be also empty, null means none. * @var string */ protected $anchor = null; /** * Url parameters as associative array. * @var array */ protected $params = []; /** * Create new instance of url. * * @param self|string $url - moodle_url means make a copy of another * moodle_url and change parameters, string means full url or shortened * form (ex.: '/course/view.php'). It is strongly encouraged to not include * query string because it may result in double encoded values. Use the * $params instead. For admin URLs, just use /admin/script.php, this * class takes care of the $CFG->admin issue. * @param null|array $params these params override current params or add new * @param string $anchor The anchor to use as part of the URL if there is one. * @throws moodle_exception */ public function __construct( $url, ?array $params = null, $anchor = null, ) { global $CFG; if ($url instanceof self) { $this->scheme = $url->scheme; $this->host = $url->host; $this->port = $url->port; $this->user = $url->user; $this->pass = $url->pass; $this->path = $url->path; $this->slashargument = $url->slashargument; $this->params = $url->params; $this->anchor = $url->anchor; } else { $url = $url ?? ''; // Detect if anchor used. $apos = strpos($url, '#'); if ($apos !== false) { $anchor = substr($url, $apos); $anchor = ltrim($anchor, '#'); $this->set_anchor($anchor); $url = substr($url, 0, $apos); } // Normalise shortened form of our url ex.: '/course/view.php'. if (strpos($url, '/') === 0) { $url = $CFG->wwwroot . $url; } if ($CFG->admin !== 'admin') { if (strpos($url, "$CFG->wwwroot/admin/") === 0) { $url = str_replace("$CFG->wwwroot/admin/", "$CFG->wwwroot/$CFG->admin/", $url); } } // Parse the $url. $parts = parse_url($url); if ($parts === false) { throw new moodle_exception('invalidurl'); } if (isset($parts['query'])) { // Note: the values may not be correctly decoded, url parameters should be always passed as array. $out = []; parse_str(str_replace('&', '&', $parts['query']), $out); $this->params($out); } unset($parts['query']); foreach ($parts as $key => $value) { $this->$key = $value; } // Detect slashargument value from path - we do not support directory names ending with .php. $pos = strpos($this->path, '.php/'); if ($pos !== false) { $this->slashargument = substr($this->path, $pos + 4); $this->path = substr($this->path, 0, $pos + 4); } } $this->params($params); if ($anchor !== null) { $this->anchor = (string)$anchor; } } /** * Add an array of params to the params for this url. * * The added params override existing ones if they have the same name. * * @param null|array $params Array of parameters to add. Note all values that are not arrays are cast to strings. * @return array Array of Params for url. * @throws coding_exception */ public function params(?array $params = null) { $params = (array)$params; $params = $this->clean_url_params($params); $this->params = array_merge($this->params, $params); return $this->params; } /** * Converts given URL parameter values that are not arrays into strings. * * This is to maintain the same behaviour as the original params() function. * * @param array $params * @return array */ private function clean_url_params(array $params): array { // Convert all values to strings. // This was the original implementation of the params function, // which we have kept for backwards compatibility. array_walk_recursive($params, function (&$value) { if (is_object($value) && !is_a($value, \Stringable::class)) { throw new coding_exception('Url parameters values can not be objects, unless __toString() is defined!'); } $value = (string) $value; }); return $params; } /** * Remove all params if no arguments passed. * Remove selected params if arguments are passed. * * Can be called as either remove_params('param1', 'param2') * or remove_params(array('param1', 'param2')). * * @param string[]|string ...$params either an array of param names, or 1..n string params to remove as args. * @return array url parameters */ public function remove_params(...$params) { if (empty($params)) { return $this->params; } $firstparam = reset($params); if (is_array($firstparam)) { $params = $firstparam; } foreach ($params as $param) { unset($this->params[$param]); } return $this->params; } /** * Remove all url parameters. * * @param array $unused Unused param */ public function remove_all_params($unused = null) { $this->params = []; $this->slashargument = ''; } /** * Add a param to the params for this url. * * The added param overrides existing one if they have the same name. * * @param string $paramname name * @param string $newvalue Param value. If new value specified current value is overriden or parameter is added * @return array|string|null parameter value, null if parameter does not exist. */ public function param($paramname, $newvalue = '') { if (func_num_args() > 1) { // Set new value. $this->params([$paramname => $newvalue]); } if (isset($this->params[$paramname])) { return $this->params[$paramname]; } else { return null; } } /** * Merges parameters. * * @param null|array $overrideparams * @return array merged parameters */ protected function merge_overrideparams(?array $overrideparams = null) { $overrideparams = (array) $overrideparams; $overrideparams = $this->clean_url_params($overrideparams); return array_merge($this->params, $overrideparams); } /** * Recursively transforms the given array of values to query string parts. * * Example query string parts: a=2, a[0]=2 * * @param array $data Data to encode into query string parts. Can be a multi level array. All end values must be strings. * @return array array of query string parts. All parts are rawurlencoded. */ private function recursively_transform_params_to_query_string_parts(array $data): array { $stringparams = []; // Define a recursive function to encode the array into a set of string params. // We need to do this recursively, so that multi level array parameters are properly supported. $parsestringparams = function (array $data) use (&$stringparams, &$parsestringparams) { foreach ($data as $key => $value) { // If this is an array, rewrite the $value keys to track the position in the array. // and pass back to this function recursively until the values are no longer arrays. // E.g. if $key is 'a' and $value was [0 => true, 1 => false] // the new array becomes ['a[0]' => true, 'a[1]' => false]. if (is_array($value)) { $newvalue = []; foreach ($value as $innerkey => $innervalue) { $newkey = $key . '[' . $innerkey . ']'; $newvalue[$newkey] = $innervalue; } $parsestringparams($newvalue); } else { // Else no more arrays to traverse - build the final query string part. // We enforce that all end values are strings for consistency. // When params() is used, it will convert all params given to strings. // This will catch out anyone setting the params property directly. if (!is_string($value)) { throw new coding_exception('Unexpected query string value type. All values that are not arrays should be a string.'); } if (isset($value) && $value !== '') { $stringparams[] = rawurlencode($key) . '=' . rawurlencode($value); } else { $stringparams[] = rawurlencode($key); } } } }; $parsestringparams($data); return $stringparams; } /** * Get the params as as a query string. * * This method should not be used outside of this method. * * @param bool $escaped Use & as params separator instead of plain & * @param null|array $overrideparams params to add to the output params, these * override existing ones with the same name. * @return string query string that can be added to a url. */ public function get_query_string($escaped = true, ?array $overrideparams = null) { if ($overrideparams !== null) { $params = $this->merge_overrideparams($overrideparams); } else { $params = $this->params; } $stringparams = $this->recursively_transform_params_to_query_string_parts($params); if ($escaped) { return implode('&', $stringparams); } else { return implode('&', $stringparams); } } /** * Get the url params as an array of key => value pairs. * * This helps in handling cases where url params contain arrays. * * @return array params array for templates. */ public function export_params_for_template(): array { $querystringparts = $this->recursively_transform_params_to_query_string_parts($this->params); return array_map(function ($value) { // First urldecode it, they are encoded by default. $value = rawurldecode($value); // Now separate the parts into name and value, splitting only on the first '=' sign. // There may be more = signs (e.g. base64, encoded urls, etc...) that we don't want to split on. $parts = explode('=', $value, 2); // Parts must be of length 1 or 2, anything else is an invalid. if (count($parts) !== 1 && count($parts) !== 2) { throw new coding_exception('Invalid query string construction, unexpected number of parts'); } // There might not always be a '=' e.g. when the value is an empty string. // in this case, just fallback to an empty string. $name = $parts[0]; $value = $parts[1] ?? ''; return ['name' => $name, 'value' => $value]; }, $querystringparts); } /** * Shortcut for printing of encoded URL. * * @return string */ public function __toString() { return $this->out(true); } /** * Output url. * * If you use the returned URL in HTML code, you want the escaped ampersands. If you use * the returned URL in HTTP headers, you want $escaped=false. * * @param bool $escaped Use & as params separator instead of plain & * @param null|array $overrideparams params to add to the output url, these override existing ones with the same name. * @return string Resulting URL */ public function out($escaped = true, ?array $overrideparams = null) { global $CFG; if (!is_bool($escaped)) { debugging('Escape parameter must be of type boolean, ' . gettype($escaped) . ' given instead.'); } $url = $this; // Allow url's to be rewritten by a plugin. if (isset($CFG->urlrewriteclass) && !isset($CFG->upgraderunning)) { $class = $CFG->urlrewriteclass; $pluginurl = $class::url_rewrite($url); if ($pluginurl instanceof url) { $url = $pluginurl; } } return $url->raw_out($escaped, $overrideparams); } /** * Output url without any rewrites * * This is identical in signature and use to out() but doesn't call the rewrite handler. * * @param bool $escaped Use & as params separator instead of plain & * @param null|array $overrideparams params to add to the output url, these override existing ones with the same name. * @return string Resulting URL */ public function raw_out($escaped = true, ?array $overrideparams = null) { if (!is_bool($escaped)) { debugging('Escape parameter must be of type boolean, ' . gettype($escaped) . ' given instead.'); } $uri = $this->out_omit_querystring() . $this->slashargument; $querystring = $this->get_query_string($escaped, $overrideparams); if ($querystring !== '') { $uri .= '?' . $querystring; } $uri .= $this->get_encoded_anchor(); return $uri; } /** * Encode the anchor according to RFC 3986. * * @return string The encoded anchor */ public function get_encoded_anchor(): string { if (is_null($this->anchor)) { return ''; } // RFC 3986 allows the following characters in a fragment without them being encoded: // pct-encoded: "%" HEXDIG HEXDIG // unreserved: ALPHA / DIGIT / "-" / "." / "_" / "~" / // sub-delims: "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" / ":" / "@" // fragment: "/" / "?" // // All other characters should be encoded. // These should not be encoded in the fragment unless they were already encoded. // The following characters are allowed in the fragment without encoding. // In addition to this list is pct-encoded, but we can't easily handle this with a regular expression. $allowed = 'a-zA-Z0-9\\-._~!$&\'()*+,;=:@\/?'; $anchor = '#'; $remainder = $this->anchor; do { // Split the string on any %. $parts = explode('%', $remainder, 2); $anchorparts = array_shift($parts); // The first part can go through our preg_replace_callback to quote any relevant characters. $anchor .= preg_replace_callback( '/[^' . $allowed . ']/', fn ($matches) => rawurlencode($matches[0]), $anchorparts, ); // The second part _might_ be a valid pct-encoded character. if (count($parts) === 0) { break; } // If the second part is a valid pct-encoded character, append it to the anchor. $remainder = array_shift($parts); if (preg_match('/^[a-fA-F0-9]{2}/', $remainder, $matches)) { $anchor .= "%{$matches[0]}"; $remainder = substr($remainder, 2); } else { // This was not a valid pct-encoded character. Encode the % and continue with the next part. $anchor .= rawurlencode('%'); } } while (strlen($remainder) > 0); return $anchor; } /** * Returns url without parameters, everything before '?'. * * @param bool $includeanchor if {@see self::anchor} is defined, should it be returned? * @return string */ public function out_omit_querystring($includeanchor = false) { $uri = $this->scheme ? $this->scheme . ':' . ((strtolower($this->scheme) == 'mailto') ? '' : '//') : ''; $uri .= $this->user ? $this->user . ($this->pass ? ':' . $this->pass : '') . '@' : ''; $uri .= $this->host ? $this->host : ''; $uri .= $this->port ? ':' . $this->port : ''; $uri .= $this->path ? $this->path : ''; if ($includeanchor) { $uri .= $this->get_encoded_anchor(); } return $uri; } /** * Compares this url with another. * * See documentation of constants for an explanation of the comparison flags. * * @param self $url The moodle_url object to compare * @param int $matchtype The type of comparison (URL_MATCH_BASE, URL_MATCH_PARAMS, URL_MATCH_EXACT) * @return bool */ public function compare(self $url, $matchtype = URL_MATCH_EXACT) { $baseself = $this->out_omit_querystring(); $baseother = $url->out_omit_querystring(); // Append index.php if there is no specific file. if (substr($baseself, -1) == '/') { $baseself .= 'index.php'; } if (substr($baseother, -1) == '/') { $baseother .= 'index.php'; } // Compare the two base URLs. if ($baseself != $baseother) { return false; } if ($matchtype == URL_MATCH_BASE) { return true; } $urlparams = $url->params(); foreach ($this->params() as $param => $value) { if ($param == 'sesskey') { continue; } if (!array_key_exists($param, $urlparams) || $urlparams[$param] != $value) { return false; } } if ($matchtype == URL_MATCH_PARAMS) { return true; } foreach ($urlparams as $param => $value) { if ($param == 'sesskey') { continue; } if (!array_key_exists($param, $this->params()) || $this->param($param) != $value) { return false; } } if ($url->anchor !== $this->anchor) { return false; } return true; } /** * Sets the anchor for the URI (the bit after the hash) * * @param string $anchor null means remove previous */ public function set_anchor($anchor) { if (is_null($anchor)) { // Remove. $this->anchor = null; } else { $this->anchor = $anchor; } } /** * Sets the scheme for the URI (the bit before ://) * * @param string $scheme */ public function set_scheme($scheme) { // See http://www.ietf.org/rfc/rfc3986.txt part 3.1. if (preg_match('/^[a-zA-Z][a-zA-Z0-9+.-]*$/', $scheme)) { $this->scheme = $scheme; } else { throw new coding_exception('Bad URL scheme.'); } } /** * Sets the url slashargument value. * * @param string $path usually file path * @param string $parameter name of page parameter if slasharguments not supported * @param bool $supported usually null, then it depends on $CFG->slasharguments, use true or false for other servers */ public function set_slashargument($path, $parameter = 'file', $supported = null) { global $CFG; if (is_null($supported)) { $supported = !empty($CFG->slasharguments); } if ($supported) { $parts = explode('/', $path); $parts = array_map('rawurlencode', $parts); $path = implode('/', $parts); $this->slashargument = $path; unset($this->params[$parameter]); } else { $this->slashargument = ''; $this->params[$parameter] = $path; } } // Static factory methods. /** * Create a new url instance from a UriInterface. * * @param UriInterface $uri * @return self */ public static function from_uri(UriInterface $uri): self { $url = new self( url: $uri->getScheme() . '://' . $uri->getAuthority() . $uri->getPath(), anchor: $uri->getFragment() ?: null, ); $params = $uri->getQuery(); foreach (explode('&', $params) as $param) { $url->param(...explode('=', $param, 2)); } return $url; } /** * Create a new moodle_url instance from routed path. * * @param string $path The routed path * @param null|array $params The path parameters * @param null|string $anchor The anchor * @return self */ public static function routed_path( string $path, ?array $params = null, ?string $anchor = null, ): self { global $CFG; if ($CFG->routerconfigured !== true) { $path = '/r.php/' . ltrim($path, '/'); } $url = new self($path, $params, $anchor); return $url; } /** * General moodle file url. * * @param string $urlbase the script serving the file * @param string $path * @param bool $forcedownload * @return self */ public static function make_file_url($urlbase, $path, $forcedownload = false) { $params = []; if ($forcedownload) { $params['forcedownload'] = 1; } $url = new self($urlbase, $params); $url->set_slashargument($path); return $url; } /** * Factory method for creation of url pointing to plugin file. * * Please note this method can be used only from the plugins to * create urls of own files, it must not be used outside of plugins! * * @param int $contextid * @param string $component * @param string $area * @param ?int $itemid * @param string $pathname * @param string $filename * @param bool $forcedownload * @param mixed $includetoken Whether to use a user token when displaying this group image. * True indicates to generate a token for current user, and integer value indicates to generate a token for the * user whose id is the value indicated. * If the group picture is included in an e-mail or some other location where the audience is a specific * user who will not be logged in when viewing, then we use a token to authenticate the user. * @return url */ public static function make_pluginfile_url( $contextid, $component, $area, $itemid, $pathname, $filename, $forcedownload = false, $includetoken = false ) { global $CFG, $USER; $path = []; if ($includetoken) { $urlbase = "$CFG->wwwroot/tokenpluginfile.php"; $userid = $includetoken === true ? $USER->id : $includetoken; $token = get_user_key('core_files', $userid); if ($CFG->slasharguments) { $path[] = $token; } } else { $urlbase = "$CFG->wwwroot/pluginfile.php"; } $path[] = $contextid; $path[] = $component; $path[] = $area; if ($itemid !== null) { $path[] = $itemid; } $path = "/" . implode('/', $path) . "{$pathname}{$filename}"; $url = self::make_file_url($urlbase, $path, $forcedownload, $includetoken); if ($includetoken && empty($CFG->slasharguments)) { $url->param('token', $token); } return $url; } /** * Factory method for creation of url pointing to plugin file. * This method is the same that make_pluginfile_url but pointing to the webservice pluginfile.php script. * It should be used only in external functions. * * @since 2.8 * @param int $contextid * @param string $component * @param string $area * @param int $itemid * @param string $pathname * @param string $filename * @param bool $forcedownload * @return url */ public static function make_webservice_pluginfile_url( $contextid, $component, $area, $itemid, $pathname, $filename, $forcedownload = false ) { global $CFG; $urlbase = "$CFG->wwwroot/webservice/pluginfile.php"; if ($itemid === null) { return self::make_file_url($urlbase, "/$contextid/$component/$area" . $pathname . $filename, $forcedownload); } else { return self::make_file_url($urlbase, "/$contextid/$component/$area/$itemid" . $pathname . $filename, $forcedownload); } } /** * Factory method for creation of url pointing to draft file of current user. * * @param int $draftid draft item id * @param string $pathname * @param string $filename * @param bool $forcedownload * @return url */ public static function make_draftfile_url($draftid, $pathname, $filename, $forcedownload = false) { global $CFG, $USER; $urlbase = "$CFG->wwwroot/draftfile.php"; $context = context_user::instance($USER->id); return self::make_file_url($urlbase, "/$context->id/user/draft/$draftid" . $pathname . $filename, $forcedownload); } /** * Factory method for creating of links to legacy course files. * * @param int $courseid * @param string $filepath * @param bool $forcedownload * @return url */ public static function make_legacyfile_url($courseid, $filepath, $forcedownload = false) { global $CFG; $urlbase = "$CFG->wwwroot/file.php"; return self::make_file_url($urlbase, '/' . $courseid . '/' . $filepath, $forcedownload); } /** * Checks if URL is relative to $CFG->wwwroot. * * @return bool True if URL is relative to $CFG->wwwroot; otherwise, false. */ public function is_local_url(): bool { global $CFG; $url = $this->out(); // Does URL start with wwwroot? Otherwise, URL isn't relative to wwwroot. return ( ($url === $CFG->wwwroot) || (strpos($url, $CFG->wwwroot . '/') === 0) ); } /** * Returns URL as relative path from $CFG->wwwroot * * Can be used for passing around urls with the wwwroot stripped * * @param boolean $escaped Use & as params separator instead of plain & * @param ?array $overrideparams params to add to the output url, these override existing ones with the same name. * @return string Resulting URL * @throws coding_exception if called on a non-local url */ public function out_as_local_url($escaped = true, ?array $overrideparams = null) { global $CFG; // URL should be relative to wwwroot. If not then throw exception. if ($this->is_local_url()) { $url = $this->out($escaped, $overrideparams); $localurl = substr($url, strlen($CFG->wwwroot)); return !empty($localurl) ? $localurl : ''; } else { throw new coding_exception('out_as_local_url called on a non-local URL'); } } /** * Returns the 'path' portion of a URL. For example, if the URL is * http://www.example.org:447/my/file/is/here.txt?really=1 then this will * return '/my/file/is/here.txt'. * * By default the path includes slash-arguments (for example, * '/myfile.php/extra/arguments') so it is what you would expect from a * URL path. If you don't want this behaviour, you can opt to exclude the * slash arguments. (Be careful: if the $CFG variable slasharguments is * disabled, these URLs will have a different format and you may need to * look at the 'file' parameter too.) * * @param bool $includeslashargument If true, includes slash arguments * @return string Path of URL */ public function get_path($includeslashargument = true) { return $this->path . ($includeslashargument ? $this->slashargument : ''); } /** * Returns a given parameter value from the URL. * * @param string $name Name of parameter * @return array|string|null Value of parameter or null if not set. */ public function get_param($name) { if (array_key_exists($name, $this->params)) { return $this->params[$name]; } else { return null; } } /** * Returns the 'scheme' portion of a URL. For example, if the URL is * http://www.example.org:447/my/file/is/here.txt?really=1 then this will * return 'http' (without the colon). * * @return string Scheme of the URL. */ public function get_scheme() { return $this->scheme; } /** * Returns the 'host' portion of a URL. For example, if the URL is * http://www.example.org:447/my/file/is/here.txt?really=1 then this will * return 'www.example.org'. * * @return string Host of the URL. */ public function get_host() { return $this->host; } /** * Returns the 'port' portion of a URL. For example, if the URL is * http://www.example.org:447/my/file/is/here.txt?really=1 then this will * return '447'. * * @return string Port of the URL. */ public function get_port() { return $this->port; } /** * Returns the 'slashargument' portion of a URL. For example, if the URL is * http://www.example.org.com/pluginfile.php/1/core_admin/logocompact/ then this will * return '1/core_admin/logocompact/'. * * @return string Slash argument as string. */ public function get_slashargument(): string { return $this->slashargument; } } // Alias this class to the old name. // This file will be autoloaded by the legacyclasses autoload system. // In future all uses of this class will be corrected and the legacy references will be removed. class_alias(url::class, \moodle_url::class);