From 75781f879c813a4c87cc6c9173c7588c792c81e8 Mon Sep 17 00:00:00 2001 From: tjhunt Date: Wed, 6 May 2009 08:50:32 +0000 Subject: [PATCH] moodle_page: MDL-12212 ->url and cleanup init of $FULLME, etc. --- lib/pagelib.php | 32 +++++ lib/setuplib.php | 148 +++++++++++++--------- lib/simpletest/testpagelib_moodlepage.php | 40 ++++++ lib/weblib.php | 61 ++++++--- 4 files changed, 200 insertions(+), 81 deletions(-) diff --git a/lib/pagelib.php b/lib/pagelib.php index 45377264d6..95af986993 100644 --- a/lib/pagelib.php +++ b/lib/pagelib.php @@ -75,6 +75,8 @@ class moodle_page { protected $_legacyclass = null; + protected $_url = null; + /// Getter methods ============================================================= /// Due to the __get magic below, you normally do not call these as $PAGE->get_x /// methods, but instead use the $PAGE->x syntax. @@ -173,6 +175,18 @@ class moodle_page { } } + /** + * @return moodle_url the clean URL required to load the current page. (You + * should normally use this in preference to $ME or $FULLME.) + */ + public function get_url() { + if (is_null($this->_url)) { + debugging('This page did no call $PAGE->set_url(...). Realying on a guess.', DEBUG_DEVELOPER); + return new moodle_url($ME); + } + return $this->_url; + } + /** * PHP overloading magic to make the $PAGE->course syntax work. */ @@ -319,6 +333,24 @@ class moodle_page { $this->_docspath = $path; } + /** + * You should call this method from every page to set the cleaned-up URL + * that should be used to return to this page. Used, for example, by the + * blocks editing UI to know where to return the user after an action. + * For example, course/view.php does: + * $id = optional_param('id', 0, PARAM_INT); + * $PAGE->set_url('course/view.php', array('id' => $id)); + * @param string $url a URL, relative to $CFG->wwwroot. + * @param array $params paramters to add ot the URL. + */ + public function set_url($url, $params = array()) { + global $CFG; + $this->_url = new moodle_url($CFG->wwwroot . '/' . $url, $params); + if (is_null($this->_pagetype)) { + $this->initialise_default_pagetype($url); + } + } + /// Initialisation methods ===================================================== /// These set various things up in a default way. diff --git a/lib/setuplib.php b/lib/setuplib.php index 3aa0a20214..3e24758a97 100644 --- a/lib/setuplib.php +++ b/lib/setuplib.php @@ -103,45 +103,107 @@ function setup_validate_php_configuration() { } /** - * Initialises $FULLME and friends. - * @return void + * Initialises $FULLME and friends. Private function. Should only be called from + * setup.php. */ function initialise_fullme() { global $CFG, $FULLME, $ME, $SCRIPT, $FULLSCRIPT; + // Detect common config error. if (substr($CFG->wwwroot, -1) == '/') { print_error('wwwrootslash', 'error'); } - $url = parse_url($CFG->wwwroot); - if (!isset($url['path'])) { - $url['path'] = ''; + if (CLI_SCRIPT) { + initialise_fullme_cli(); + return; } - $url['path'] .= '/'; - if (CLI_SCRIPT) { - // urls do not make much sense in CLI scripts - $backtrace = debug_backtrace(); - $topfile = array_pop($backtrace); - $topfile = realpath($topfile['file']); - $dirroot = realpath($CFG->dirroot); - - if (strpos($topfile, $dirroot) !== 0) { - $SCRIPT = $FULLSCRIPT = $FULLME = $ME = null; - } else { - $relme = substr($topfile, strlen($dirroot)); - $relme = str_replace('\\', '/', $relme); // Win fix - $SCRIPT = $FULLSCRIPT = $FULLME = $ME = $relme; - } + $wwwroot = parse_url($CFG->wwwroot); + if (!isset($wwwroot['path'])) { + $wwwroot['path'] = ''; + } + $wwwroot['path'] .= '/'; + + $rurl = setup_get_remote_url(); + // Check that URL is under $CFG->wwwroot. + if (strpos($rurl['path'], $wwwroot['path']) === 0) { + $SCRIPT = substr($rurl['path'], strlen($wwwroot['path'])-1); + } else { + // Probably some weird external script + $SCRIPT = $FULLSCRIPT = $FULLME = $ME = null; return; } + // $CFG->sslproxy specifies if external SSL appliance is used + // (That is, the Moodle server uses http, with an external box translating everything to https). + if (empty($CFG->sslproxy)) { + if ($rurl['scheme'] == 'http' and $wwwroot['scheme'] == 'https') { + print_error('sslonlyaccess', 'error'); + } + } + + // $CFG->reverseproxy specifies if reverse proxy server used. + // Used in load balancing scenarios. + // Do not abuse this to try to solve lan/wan access problems!!!!! + if (empty($CFG->reverseproxy)) { + if (($rurl['host'] != $wwwroot['host']) or + (!empty($wwwroot['port']) and $rurl['port'] != $wwwroot['port'])) { + print_error('wwwrootmismatch', 'error', '', $CFG->wwwroot); + } + } + + // hopefully this will stop all those "clever" admins trying to set up moodle + // with two different addresses in intranet and Internet + if (!empty($CFG->reverseproxy) && $rurl['host'] == $wwwroot['host']) { + print_error('reverseproxyabused', 'error'); + } + + $hostandport = $rurl['scheme'] . '://' . $wwwroot['host']; + if (!empty($wwwroot['port'])) { + $hostandport .= ':'.$wwwroot['port']; + } + + $FULLSCRIPT = $hostandport . $rurl['path']; + $FULLME = $hostandport . $rurl['fullpath']; + $ME = $rurl['fullpath']; + $rurl['path'] = $rurl['fullpath']; +} + +/** + * Initialises $FULLME and friends for command line scripts. + * This is a private method for use by initialise_fullme. + */ +function initialise_fullme_cli() { + // Urls do not make much sense in CLI scripts + $backtrace = debug_backtrace(); + $topfile = array_pop($backtrace); + $topfile = realpath($topfile['file']); + $dirroot = realpath($CFG->dirroot); + + if (strpos($topfile, $dirroot) !== 0) { + // Probably some weird external script + $SCRIPT = $FULLSCRIPT = $FULLME = $ME = null; + } else { + $relativefile = substr($topfile, strlen($dirroot)); + $relativefile = str_replace('\\', '/', $relativefile); // Win fix + $SCRIPT = $FULLSCRIPT = $relativefile; + $FULLME = $ME = null; + } +} + +/** + * Get the URL that PHP/the web server thinks it is serving. Private function + * used by initialise_fullme. In your code, use $PAGE->url, $SCRIPT, etc. + * @return array in the same format that parse_url returns, with the addition of + * a 'fullpath' element, which includes any slasharguments path. + */ +function setup_get_remote_url() { $rurl = array(); - $hostport = explode(':', $_SERVER['HTTP_HOST']); - $rurl['host'] = reset($hostport); + list($rurl['host']) = explode(':', $_SERVER['HTTP_HOST']); $rurl['port'] = $_SERVER['SERVER_PORT']; - $rurl['path'] = $_SERVER['SCRIPT_NAME']; // script path without slash arguments + $rurl['path'] = $_SERVER['SCRIPT_NAME']; // Script path without slash arguments if (stripos($_SERVER['SERVER_SOFTWARE'], 'apache') !== false) { //Apache server @@ -168,45 +230,9 @@ function initialise_fullme() { $_SERVER['REQUEST_URI'] = $rurl['fullpath']; // extra IIS compatibility } else { - print_error('unsupportedwebserver', 'error', '', $_SERVER['SERVER_SOFTWARE']); + throw new moodle_exception('unsupportedwebserver', 'error', '', $_SERVER['SERVER_SOFTWARE']); } - - if (strpos($rurl['path'], $url['path']) === 0) { - $SCRIPT = substr($rurl['path'], strlen($url['path'])-1); - } else { - // probably some weird external script - $SCRIPT = $FULLSCRIPT = $FULLME = $ME = null; - return; - } - - // $CFG->sslproxy specifies if external SSL apliance is used (server using http, ext box translating everything to https) - if (empty($CFG->sslproxy)) { - if ($rurl['scheme'] == 'http' and $url['scheme'] == 'https') { - print_error('sslonlyaccess', 'error'); - } - } - - // $CFG->reverseproxy specifies if reverse proxy server used - used in advanced load balancing setups only! - // this is not supposed to solve lan/wan access problems!!!!! - if (empty($CFG->reverseproxy)) { - if (($rurl['host'] != $url['host']) or (!empty($url['port']) and $rurl['port'] != $url['port'])) { - print_error('wwwrootmismatch', 'error', '', $CFG->wwwroot); - } - } else { - if ($rurl['host'] == $url['host']) { - // hopefully this will stop all those "clever" admins trying to set up moodle with two different addresses in intranet and Internet - print_error('reverseproxyabused', 'error'); - } - } - - $FULLME = $rurl['scheme'].'://'.$url['host']; - if (!empty($url['port'])) { - $FULLME .= ':'.$url['port']; - } - $FULLSCRIPT = $FULLME.$rurl['path']; - $FULLME = $FULLME.$rurl['fullpath']; - $ME = $rurl['fullpath']; - + return $rurl; } /** diff --git a/lib/simpletest/testpagelib_moodlepage.php b/lib/simpletest/testpagelib_moodlepage.php index 43313e288e..2f4d1f85d3 100644 --- a/lib/simpletest/testpagelib_moodlepage.php +++ b/lib/simpletest/testpagelib_moodlepage.php @@ -271,6 +271,46 @@ class moodle_page_test extends UnitTestCase { // Validate $this->assertEqual('a/page/type', $this->testpage->docspath); } + + public function test_set_url_root() { + global $CFG; + // Exercise SUT + $this->testpage->set_url(''); + // Validate + $this->assertEqual($CFG->wwwroot . '/', $this->testpage->url->out()); + } + + public function test_set_url_one_param() { + global $CFG; + // Exercise SUT + $this->testpage->set_url('mod/quiz/attempt.php', array('attempt' => 123)); + // Validate + $this->assertEqual($CFG->wwwroot . '/mod/quiz/attempt.php?attempt=123', $this->testpage->url->out()); + } + + public function test_set_url_two_params() { + global $CFG; + // Exercise SUT + $this->testpage->set_url('mod/quiz/attempt.php', array('attempt' => 123, 'page' => 7)); + // Validate + $this->assertEqual($CFG->wwwroot . '/mod/quiz/attempt.php?attempt=123&page=7', $this->testpage->url->out()); + } + + public function test_set_url_sets_page_type() { + // Exercise SUT + $this->testpage->set_url('mod/quiz/attempt.php', array('attempt' => 123, 'page' => 7)); + // Validate + $this->assertEqual('mod-quiz-attempt', $this->testpage->pagetype); + } + + public function test_set_url_does_not_change_explicit_page_type() { + // Setup fixture + $this->testpage->set_pagetype('a-page-type'); + // Exercise SUT + $this->testpage->set_url('mod/quiz/attempt.php', array('attempt' => 123, 'page' => 7)); + // Validate + $this->assertEqual('a-page-type', $this->testpage->pagetype); + } } /** diff --git a/lib/weblib.php b/lib/weblib.php index 6050e07940..571bc2d351 100644 --- a/lib/weblib.php +++ b/lib/weblib.php @@ -241,21 +241,38 @@ class moodle_url { /** * Pass no arguments to create a url that refers to this page. Use empty string to create empty url. * - * @param string $url url default null means use this page url with no query string - * empty string means empty url. If you pass any other type of url it will - * be parsed into it's bits, including query string + * @param mixed $url a number of different forms are accespted: + * null - create a URL that is the same as the URL used to load this page, but with no query string + * '' - and empty URL + * string - a URL, will be parsed into it's bits, including query string + * array - as returned from the PHP function parse_url + * moodle_url - make a copy of another moodle_url * @param array $params these params override anything in the query string * where params have the same name. */ public function __construct($url = null, $params = array()) { - global $ME; - if ($url !== '') { + if ($url === '') { + // Leave URL blank. + } else if (is_a($url, 'moodle_url')) { + $this->scheme = $url->scheme; + $this->host = $url->host; + $this->port = $url->port; + $this->user = $url->user; + $this->pass = $url->pass; + $this->path = $url->pass; + $this->fragment = $url->fragment; + $this->params = $url->params; + } else { if ($url === null) { + global $ME; $url = $ME; } - $parts = parse_url($url); + if (is_string($url)) { + $url = parse_url($url); + } + $parts = $url; if ($parts === FALSE) { - print_error('invalidurl'); + throw new moodle_exception('invalidurl'); } if (isset($parts['query'])) { parse_str(str_replace('&', '&', $parts['query']), $this->params); @@ -264,8 +281,8 @@ class moodle_url { foreach ($parts as $key => $value) { $this->$key = $value; } - $this->params($params); } + $this->params($params); } /** @@ -284,21 +301,25 @@ class moodle_url { } /** - * Remove all params if no arguments passed. Or else remove param $arg1, $arg2, etc. + * 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 $arg1 - * @param string $arg2 - * @param string $arg3 + * @param mixed $params either an array of param names, or a string param name, + * @param string $params,... any number of additional param names. */ - public function remove_params() { - if ($thisargs = func_get_args()) { - foreach ($thisargs as $arg) { - if (isset($this->params[$arg])) { - unset($this->params[$arg]); - } - } - } else { // no args + public function remove_params($params) { + if (empty($params)) { $this->params = array(); + return; + } + if (!is_array($params)) { + $params = func_get_args(); + } + foreach ($params as $param) { + if (isset($this->params[$param])) { + unset($this->params[$param]); + } } } -- 2.39.5