Merge branch 'MDL-43785-master' of git://github.com/andrewnicols/moodle
authorDan Poltawski <dan@moodle.com>
Mon, 27 Jul 2015 13:49:18 +0000 (14:49 +0100)
committerDan Poltawski <dan@moodle.com>
Mon, 27 Jul 2015 13:49:18 +0000 (14:49 +0100)
32 files changed:
auth/ldap/auth.php
availability/classes/multiple_messages.php
course/togglecompletion.php
enrol/index.php
error/index.php
lang/en/cache.php
lib/classes/session/manager.php
lib/db/caches.php
lib/deprecatedlib.php
lib/medialib.php
lib/moodlelib.php
lib/navigationlib.php
lib/tests/medialib_test.php
lib/tests/moodlelib_test.php
lib/upgrade.txt
lib/weblib.php
login/index.php
mod/choice/view.php
mod/forum/lib.php
mod/forum/markposts.php
mod/forum/post.php
mod/forum/settracking.php
mod/forum/subscribe.php
mod/quiz/renderer.php
mod/resource/view.php
mod/survey/save.php
mod/url/view.php
mod/wiki/filesedit.php
report/participation/index.php
user/classes/output/myprofile/manager.php
user/view.php
version.php

index 6090ebd..c2beb4f 100644 (file)
@@ -1642,7 +1642,7 @@ class auth_plugin_ldap extends auth_plugin_base {
 
         if (($_SERVER['REQUEST_METHOD'] === 'GET'         // Only on initial GET of loginpage
              || ($_SERVER['REQUEST_METHOD'] === 'POST'
-                 && (get_referer() != strip_querystring(qualified_me()))))
+                 && (get_local_referer() != strip_querystring(qualified_me()))))
                                                           // Or when POSTed from another place
                                                           // See MDL-14071
             && !empty($this->config->ntlmsso_enabled)     // SSO enabled
@@ -1653,13 +1653,15 @@ class auth_plugin_ldap extends auth_plugin_base {
 
             // First, let's remember where we were trying to get to before we got here
             if (empty($SESSION->wantsurl)) {
-                $SESSION->wantsurl = (array_key_exists('HTTP_REFERER', $_SERVER) &&
-                                      $_SERVER['HTTP_REFERER'] != $CFG->wwwroot &&
-                                      $_SERVER['HTTP_REFERER'] != $CFG->wwwroot.'/' &&
-                                      $_SERVER['HTTP_REFERER'] != $CFG->httpswwwroot.'/login/' &&
-                                      $_SERVER['HTTP_REFERER'] != $CFG->httpswwwroot.'/login/index.php' &&
-                                      clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL) != '')
-                    ? $_SERVER['HTTP_REFERER'] : NULL;
+                $SESSION->wantsurl = null;
+                $referer = get_safe_referer(false);
+                if ($referer &&
+                        $referer != $CFG->wwwroot &&
+                        $referer != $CFG->wwwroot . '/' &&
+                        $referer != $CFG->httpswwwroot . '/login/' &&
+                        $referer != $CFG->httpswwwroot . '/login/index.php') {
+                    $SESSION->wantsurl = $referer;
+                }
             }
 
             // Now start the whole NTLM machinery.
index 1a478f6..0ba70a7 100644 (file)
@@ -22,7 +22,7 @@
  * using bulleted lists.
  *
  * The tree structure of this object matches that of the availability
- * restrictions. 
+ * restrictions.
  *
  * @package core_availability
  * @copyright 2015 Andrew Nicols <andrew@nicols.co.uk>
@@ -37,7 +37,7 @@
  * using bulleted lists.
  *
  * The tree structure of this object matches that of the availability
- * restrictions. 
+ * restrictions.
  *
  * @package core_availability
  * @copyright 2015 Andrew Nicols <andrew@nicols.co.uk>
index 075134f..f0c77c9 100644 (file)
@@ -78,7 +78,7 @@ if ($courseid) {
         }
 
         // Return to previous page
-        $referer = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+        $referer = get_local_referer(false);
         if (!empty($referer)) {
             redirect($referer);
         } else {
index 5e3d331..dcc4d96 100644 (file)
@@ -29,7 +29,7 @@ $id = required_param('id', PARAM_INT);
 $returnurl = optional_param('returnurl', 0, PARAM_LOCALURL);
 
 if (!isloggedin()) {
-    $referer = clean_param(get_referer(), PARAM_LOCALURL);
+    $referer = get_local_referer();
     if (empty($referer)) {
         // A user that is not logged in has arrived directly on this page,
         // they should be redirected to the course page they are trying to enrol on after logging in.
@@ -108,7 +108,7 @@ if (!$forms) {
     } else if ($returnurl) {
         notice(get_string('notenrollable', 'enrol'), $returnurl);
     } else {
-        $url = clean_param(get_referer(false), PARAM_LOCALURL);
+        $url = get_local_referer(false);
         if (empty($url)) {
             $url = new moodle_url('/index.php');
         }
index 54f0b53..721f141 100644 (file)
@@ -29,7 +29,7 @@
 
     $site = get_site();
     $redirecturl = empty($_SERVER['REDIRECT_URL']) ? '' : $_SERVER['REDIRECT_URL'];
-    $httpreferer = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER'];
+    $httpreferer = get_local_referer(false);
     $requesturi  = empty($_SERVER['REQUEST_URI'])  ? '' : $_SERVER['REQUEST_URI'];
 
     header("HTTP/1.0 404 Not Found");
index f4e9312..731a5b0 100644 (file)
@@ -56,6 +56,7 @@ $string['cachedef_langmenu'] = 'List of available languages';
 $string['cachedef_locking'] = 'Locking';
 $string['cachedef_navigation_expandcourse'] = 'Navigation expandable courses';
 $string['cachedef_observers'] = 'Event observers';
+$string['cachedef_plugin_functions'] = 'Plugins available callbacks';
 $string['cachedef_plugin_manager'] = 'Plugin info manager';
 $string['cachedef_questiondata'] = 'Question definitions';
 $string['cachedef_repositories'] = 'Repositories instances data';
index 8dfc9ce..b1a5e16 100644 (file)
@@ -380,11 +380,12 @@ class manager {
             if (is_web_crawler()) {
                 $user = guest_user();
             }
-            if (!empty($CFG->guestloginbutton) and !$user and !empty($_SERVER['HTTP_REFERER'])) {
+            $referer = get_local_referer(false);
+            if (!empty($CFG->guestloginbutton) and !$user and !empty($referer)) {
                 // Automatically log in users coming from search engine results.
-                if (strpos($_SERVER['HTTP_REFERER'], 'google') !== false ) {
+                if (strpos($referer, 'google') !== false ) {
                     $user = guest_user();
-                } else if (strpos($_SERVER['HTTP_REFERER'], 'altavista') !== false ) {
+                } else if (strpos($referer, 'altavista') !== false ) {
                     $user = guest_user();
                 }
             }
index 6701e12..45599cc 100644 (file)
@@ -249,4 +249,15 @@ $definitions = array(
         'simplekeys' => true,
         'simpledata' => true,
     ),
+
+    // Caches plugins existing functions by function name and file.
+    // Set static acceleration size to 5 to load a few functions.
+    'plugin_functions' => array(
+        'mode' => cache_store::MODE_APPLICATION,
+        'simplekeys' => true,
+        'simpledata' => true,
+        'staticacceleration' => true,
+        'staticaccelerationsize' => 5
+    )
+
 );
index 1971bdc..8c85c9d 100644 (file)
@@ -2359,3 +2359,23 @@ function get_timezone_record($timezonename) {
 }
 
 /* === Apis deprecated since Moodle 3.0 === */
+/**
+ * Returns the URL of the HTTP_REFERER, less the querystring portion if required.
+ *
+ * @deprecated since Moodle 3.0 MDL-49360 - please do not use this function any more.
+ * @todo Remove this function in Moodle 3.2
+ * @param boolean $stripquery if true, also removes the query part of the url.
+ * @return string The resulting referer or empty string.
+ */
+function get_referer($stripquery = true) {
+    debugging('get_referer() is deprecated. Please use get_local_referer() instead.', DEBUG_DEVELOPER);
+    if (isset($_SERVER['HTTP_REFERER'])) {
+        if ($stripquery) {
+            return strip_querystring($_SERVER['HTTP_REFERER']);
+        } else {
+            return $_SERVER['HTTP_REFERER'];
+        }
+    } else {
+        return '';
+    }
+}
\ No newline at end of file
index 9725e35..34c2829 100644 (file)
@@ -899,7 +899,7 @@ OET;
     }
 
     public function get_rank() {
-        return 50;
+        return 10;
     }
 }
 
@@ -1141,7 +1141,7 @@ OET;
     }
 
     public function get_rank() {
-        return 20;
+        return 50;
     }
 }
 
@@ -1222,7 +1222,7 @@ OET;
     }
 
     public function get_rank() {
-        return 10;
+        return 20;
     }
 }
 
index be87bbc..72b62b0 100644 (file)
@@ -2558,8 +2558,10 @@ function require_login($courseorid = null, $autologinguest = true, $cm = null, $
             if ($setwantsurltome) {
                 $SESSION->wantsurl = qualified_me();
             }
-            if (!empty($_SERVER['HTTP_REFERER'])) {
-                $SESSION->fromurl  = $_SERVER['HTTP_REFERER'];
+
+            $referer = get_local_referer(false);
+            if (!empty($referer)) {
+                $SESSION->fromurl = $referer;
             }
 
             // Give auth plugins an opportunity to authenticate or redirect to an external login page
@@ -3989,8 +3991,11 @@ function delete_user(stdClass $user) {
     // Force logout - may fail if file based sessions used, sorry.
     \core\session\manager::kill_user_sessions($user->id);
 
+    // Generate username from email address, or a fake email.
+    $delemail = !empty($user->email) ? $user->email : $user->username . '.' . $user->id . '@unknownemail.invalid';
+    $delname = clean_param($delemail . "." . time(), PARAM_USERNAME);
+
     // Workaround for bulk deletes of users with the same email address.
-    $delname = clean_param($user->email . "." . time(), PARAM_USERNAME);
     while ($DB->record_exists('user', array('username' => $delname))) { // No need to use mnethostid here.
         $delname++;
     }
@@ -4849,10 +4854,12 @@ function remove_course_contents($courseid, $showfeedback = true, array $options
 
     // Cleanup the rest of plugins.
     $cleanuplugintypes = array('report', 'coursereport', 'format');
+    $callbacks = get_plugins_with_function('delete_course', 'lib.php');
     foreach ($cleanuplugintypes as $type) {
-        $plugins = get_plugin_list_with_function($type, 'delete_course', 'lib.php');
-        foreach ($plugins as $plugin => $pluginfunction) {
-            $pluginfunction($course->id, $showfeedback);
+        if (!empty($callbacks[$type])) {
+            foreach ($callbacks[$type] as $pluginfunction) {
+                $pluginfunction($course->id, $showfeedback);
+            }
         }
         if ($showfeedback) {
             echo $OUTPUT->notification($strdeleted.get_string('type_'.$type.'_plural', 'plugin'), 'notifysuccess');
@@ -7029,26 +7036,122 @@ function is_valid_plugin_name($name) {
  *      and the function names as values (e.g. 'report_courselist_hook', 'forum_hook').
  */
 function get_plugin_list_with_function($plugintype, $function, $file = 'lib.php') {
+    global $CFG;
+
+    // We don't include here as all plugin types files would be included.
+    $plugins = get_plugins_with_function($function, $file, false);
+
+    if (empty($plugins[$plugintype])) {
+        return array();
+    }
+
+    $allplugins = core_component::get_plugin_list($plugintype);
+
+    // Reformat the array and include the files.
     $pluginfunctions = array();
-    $pluginswithfile = core_component::get_plugin_list_with_file($plugintype, $file, true);
-    foreach ($pluginswithfile as $plugin => $notused) {
-        $fullfunction = $plugintype . '_' . $plugin . '_' . $function;
+    foreach ($plugins[$plugintype] as $pluginname => $functionname) {
 
-        if (function_exists($fullfunction)) {
-            // Function exists with standard name. Store, indexed by frankenstyle name of plugin.
-            $pluginfunctions[$plugintype . '_' . $plugin] = $fullfunction;
+        // Check that it has not been removed and the file is still available.
+        if (!empty($allplugins[$pluginname])) {
 
-        } else if ($plugintype === 'mod') {
-            // For modules, we also allow plugin without full frankenstyle but just starting with the module name.
-            $shortfunction = $plugin . '_' . $function;
-            if (function_exists($shortfunction)) {
-                $pluginfunctions[$plugintype . '_' . $plugin] = $shortfunction;
+            $filepath = $allplugins[$pluginname] . DIRECTORY_SEPARATOR . $file;
+            if (file_exists($filepath)) {
+                include_once($filepath);
+                $pluginfunctions[$plugintype . '_' . $pluginname] = $functionname;
             }
         }
     }
+
     return $pluginfunctions;
 }
 
+/**
+ * Get a list of all the plugins that define a certain API function in a certain file.
+ *
+ * @param string $function the part of the name of the function after the
+ *      frankenstyle prefix. e.g 'hook' if you are looking for functions with
+ *      names like report_courselist_hook.
+ * @param string $file the name of file within the plugin that defines the
+ *      function. Defaults to lib.php.
+ * @param bool $include Whether to include the files that contain the functions or not.
+ * @return array with [plugintype][plugin] = functionname
+ */
+function get_plugins_with_function($function, $file = 'lib.php', $include = true) {
+    global $CFG;
+
+    $cache = \cache::make('core', 'plugin_functions');
+
+    // Including both although I doubt that we will find two functions definitions with the same name.
+    // Clearning the filename as cache_helper::hash_key only allows a-zA-Z0-9_.
+    $key = $function . '_' . clean_param($file, PARAM_ALPHA);
+
+    if ($pluginfunctions = $cache->get($key)) {
+
+        // Checking that the files are still available.
+        foreach ($pluginfunctions as $plugintype => $plugins) {
+
+            $allplugins = \core_component::get_plugin_list($plugintype);
+            foreach ($plugins as $plugin => $fullpath) {
+
+                // Cache might be out of sync with the codebase, skip the plugin if it is not available.
+                if (empty($allplugins[$plugin])) {
+                    unset($pluginfunctions[$plugintype][$plugin]);
+                    continue;
+                }
+
+                $fileexists = file_exists($allplugins[$plugin] . DIRECTORY_SEPARATOR . $file);
+                if ($include && $fileexists) {
+                    // Include the files if it was requested.
+                    include_once($allplugins[$plugin] . DIRECTORY_SEPARATOR . $file);
+                } else if (!$fileexists) {
+                    // If the file is not available any more it should not be returned.
+                    unset($pluginfunctions[$plugintype][$plugin]);
+                }
+            }
+        }
+        return $pluginfunctions;
+    }
+
+    $pluginfunctions = array();
+
+    // To fill the cached. Also, everything should continue working with cache disabled.
+    $plugintypes = \core_component::get_plugin_types();
+    foreach ($plugintypes as $plugintype => $unused) {
+
+        // We need to include files here.
+        $pluginswithfile = \core_component::get_plugin_list_with_file($plugintype, $file, true);
+        foreach ($pluginswithfile as $plugin => $notused) {
+
+            $fullfunction = $plugintype . '_' . $plugin . '_' . $function;
+
+            $pluginfunction = false;
+            if (function_exists($fullfunction)) {
+                // Function exists with standard name. Store, indexed by frankenstyle name of plugin.
+                $pluginfunction = $fullfunction;
+
+            } else if ($plugintype === 'mod') {
+                // For modules, we also allow plugin without full frankenstyle but just starting with the module name.
+                $shortfunction = $plugin . '_' . $function;
+                if (function_exists($shortfunction)) {
+                    $pluginfunction = $shortfunction;
+                }
+            }
+
+            if ($pluginfunction) {
+                if (empty($pluginfunctions[$plugintype])) {
+                    $pluginfunctions[$plugintype] = array();
+                }
+                $pluginfunctions[$plugintype][$plugin] = $pluginfunction;
+            }
+
+        }
+    }
+    $cache->set($key, $pluginfunctions);
+
+    return $pluginfunctions;
+
+}
+
 /**
  * Lists plugin-like directories within specified directory
  *
index 549eb6d..33c2ad5 100644 (file)
@@ -3915,10 +3915,12 @@ class settings_navigation extends navigation_node {
             }
         }
 
-        // Let admin tools hook into course navigation.
-        $tools = get_plugin_list_with_function('tool', 'extend_navigation_course', 'lib.php');
-        foreach ($tools as $toolfunction) {
-            $toolfunction($coursenode, $course, $coursecontext);
+        // Let plugins hook into course navigation.
+        $pluginsfunction = get_plugins_with_function('extend_navigation_course', 'lib.php');
+        foreach ($pluginsfunction as $plugintype => $plugins) {
+            foreach ($plugins as $pluginfunction) {
+                $pluginfunction($coursenode, $course, $coursecontext);
+            }
         }
 
         // Return we are done
@@ -4484,10 +4486,12 @@ class settings_navigation extends navigation_node {
             }
         }
 
-        // Let admin tools hook into user settings navigation.
-        $tools = get_plugin_list_with_function('tool', 'extend_navigation_user_settings', 'lib.php');
-        foreach ($tools as $toolfunction) {
-            $toolfunction($usersetting, $user, $usercontext, $course, $coursecontext);
+        // Let plugins hook into user settings navigation.
+        $pluginsfunction = get_plugins_with_function('extend_navigation_user_settings', 'lib.php');
+        foreach ($pluginsfunction as $plugintype => $plugins) {
+            foreach ($plugins as $pluginfunction) {
+                $pluginfunction($usersetting, $user, $usercontext, $course, $coursecontext);
+            }
         }
 
         return $usersetting;
@@ -4717,10 +4721,12 @@ class settings_navigation extends navigation_node {
             $frontpage->add(get_string('sitelegacyfiles'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/folder', ''));
         }
 
-        // Let admin tools hook into frontpage navigation.
-        $tools = get_plugin_list_with_function('tool', 'extend_navigation_frontpage', 'lib.php');
-        foreach ($tools as $toolfunction) {
-            $toolfunction($frontpage, $course, $coursecontext);
+        // Let plugins hook into frontpage navigation.
+        $pluginsfunction = get_plugins_with_function('extend_navigation_frontpage', 'lib.php');
+        foreach ($pluginsfunction as $plugintype => $plugins) {
+            foreach ($plugins as $pluginfunction) {
+                $pluginfunction($frontpage, $course, $coursecontext);
+            }
         }
 
         return $frontpage;
index ed19db7..7129e80 100644 (file)
@@ -168,6 +168,13 @@ class core_medialib_testcase extends advanced_testcase {
         $CFG->core_media_enable_mp3 = true;
         $renderer = new core_media_renderer_test($PAGE, '');
         $this->assertSame('mp3, html5audio, link', $renderer->get_players_test());
+
+        // Test QT and HTML5 media order.
+        $CFG->core_media_enable_mp3 = false;
+        $CFG->core_media_enable_html5video = true;
+        $CFG->core_media_enable_qt = true;
+        $renderer = new core_media_renderer_test($PAGE, '');
+        $this->assertSame('html5video, html5audio, qt, link', $renderer->get_players_test());
     }
 
     /**
@@ -210,6 +217,13 @@ class core_medialib_testcase extends advanced_testcase {
     public function test_embed_url_fallbacks() {
         global $CFG, $PAGE;
 
+        // Key strings in the embed code that identify with the media formats being tested.
+        $qt = 'qtplugin.cab';
+        $html5video = '</video>';
+        $html5audio = '</audio>';
+        $link = 'mediafallbacklink';
+        $mp3 = 'mediaplugin_mp3';
+
         $url = new moodle_url('http://example.org/test.mp4');
 
         // All plugins disabled, NOLINK option.
@@ -222,59 +236,58 @@ class core_medialib_testcase extends advanced_testcase {
         // All plugins disabled but not NOLINK.
         $renderer = new core_media_renderer_test($PAGE, '');
         $t = $renderer->embed_url($url);
-        $this->assert_contents(false, false, true, $t);
+        $this->assertContains($link, $t);
 
-        // HTML5 plugin enabled.
+        // Enable media players that can play the same media formats. (ie. qt & html5video for mp4 files, etc.)
         $CFG->core_media_enable_html5video = true;
-        $renderer = new core_media_renderer_test($PAGE, '');
-        $t = $renderer->embed_url($url);
-        $this->assert_contents(false, true, true, $t);
-
-        // QT plugin enabled as well.
+        $CFG->core_media_enable_html5audio = true;
+        $CFG->core_media_enable_mp3 = true;
         $CFG->core_media_enable_qt = true;
-        $renderer = new core_media_renderer_test($PAGE, '');
-        $t = $renderer->embed_url($url);
-        $this->assert_contents(true, true, true, $t);
 
-        // Nolink turned off, plugins still enabled.
-        $t = $renderer->embed_url($url, 0, 0, '',
-                array(core_media::OPTION_NO_LINK => true));
-        $this->assert_contents(true, true, false, $t);
-    }
-
-    /**
-     * Checks the contents of the resulting HTML code to ensure it used the
-     * correct embed method(s).
-     *
-     * @param bool $hasqt True if it should have QT embed code
-     * @param bool $hashtml5 True if it should have HTML5 embed code
-     * @param bool $haslink True if it should have a fallback link
-     * @param string $text HTML content
-     */
-    private function assert_contents($hasqt, $hashtml5, $haslink, $text) {
-        // I tried to avoid making it specific to the exact details of the html
-        // code, picking out only single key strings that would let it check
-        // whether final code contains the right things.
-        $qt = 'qtplugin.cab';
-        $html5 = '</video>';
-        $link = 'mediafallbacklink';
-
-        if ($hasqt) {
-            $this->assertContains($qt, $text);
-        } else {
-            $this->assertNotContains($qt, $text);
-        }
-
-        if ($hashtml5) {
-            $this->assertContains($html5, $text);
-        } else {
-            $this->assertNotContains($html5, $text);
-        }
-
-        if ($haslink) {
-            $this->assertContains($link, $text);
-        } else {
-            $this->assertNotContains($link, $text);
+        // Test media formats that can be played by 2 or more players.
+        $mediaformats = array('mp3', 'm4a', 'mp4', 'm4v');
+
+        foreach ($mediaformats as $format) {
+            $url = new moodle_url('http://example.org/test.' . $format);
+            $renderer = new core_media_renderer_test($PAGE, '');
+            $textwithlink = $renderer->embed_url($url);
+            $textwithoutlink = $renderer->embed_url($url, 0, 0, '', array(core_media::OPTION_NO_LINK => true));
+
+            switch ($format) {
+                case 'mp3':
+                    $this->assertContains($mp3, $textwithlink);
+                    $this->assertContains($html5audio, $textwithlink);
+                    $this->assertContains($link, $textwithlink);
+
+                    $this->assertContains($mp3, $textwithoutlink);
+                    $this->assertContains($html5audio, $textwithoutlink);
+                    $this->assertNotContains($link, $textwithoutlink);
+                    break;
+
+                case 'm4a':
+                    $this->assertContains($qt, $textwithlink);
+                    $this->assertContains($html5audio, $textwithlink);
+                    $this->assertContains($link, $textwithlink);
+
+                    $this->assertContains($qt, $textwithoutlink);
+                    $this->assertContains($html5audio, $textwithoutlink);
+                    $this->assertNotContains($link, $textwithoutlink);
+                    break;
+
+                case 'mp4':
+                case 'm4v':
+                    $this->assertContains($qt, $textwithlink);
+                    $this->assertContains($html5video, $textwithlink);
+                    $this->assertContains($link, $textwithlink);
+
+                    $this->assertContains($qt, $textwithoutlink);
+                    $this->assertContains($html5video, $textwithoutlink);
+                    $this->assertNotContains($link, $textwithoutlink);
+                    break;
+
+                default:
+                    break;
+            }
         }
     }
 
index 3d33588..8ee6dd2 100644 (file)
@@ -1882,6 +1882,10 @@ class core_moodlelib_testcase extends advanced_testcase {
 
         $user = $this->getDataGenerator()->create_user(array('idnumber'=>'abc'));
         $user2 = $this->getDataGenerator()->create_user(array('idnumber'=>'xyz'));
+        $usersharedemail1 = $this->getDataGenerator()->create_user(array('email' => 'sharedemail@example.invalid'));
+        $usersharedemail2 = $this->getDataGenerator()->create_user(array('email' => 'sharedemail@example.invalid'));
+        $useremptyemail1 = $this->getDataGenerator()->create_user(array('email' => ''));
+        $useremptyemail2 = $this->getDataGenerator()->create_user(array('email' => ''));
 
         // Delete user and capture event.
         $sink = $this->redirectEvents();
@@ -1947,6 +1951,30 @@ class core_moodlelib_testcase extends advanced_testcase {
         $result = delete_user($admin);
         $this->assertFalse($result);
 
+        // Simultaneously deleting users with identical email addresses.
+        $result1 = delete_user($usersharedemail1);
+        $result2 = delete_user($usersharedemail2);
+
+        $usersharedemail1after = $DB->get_record('user', array('id' => $usersharedemail1->id));
+        $usersharedemail2after = $DB->get_record('user', array('id' => $usersharedemail2->id));
+        $this->assertTrue($result1);
+        $this->assertTrue($result2);
+        $this->assertStringStartsWith($usersharedemail1->email . '.', $usersharedemail1after->username);
+        $this->assertStringStartsWith($usersharedemail2->email . '.', $usersharedemail2after->username);
+
+        // Simultaneously deleting users without email addresses.
+        $result1 = delete_user($useremptyemail1);
+        $result2 = delete_user($useremptyemail2);
+
+        $useremptyemail1after = $DB->get_record('user', array('id' => $useremptyemail1->id));
+        $useremptyemail2after = $DB->get_record('user', array('id' => $useremptyemail2->id));
+        $this->assertTrue($result1);
+        $this->assertTrue($result2);
+        $this->assertStringStartsWith($useremptyemail1->username . '.' . $useremptyemail1->id . '@unknownemail.invalid.',
+            $useremptyemail1after->username);
+        $this->assertStringStartsWith($useremptyemail2->username . '.' . $useremptyemail2->id . '@unknownemail.invalid.',
+            $useremptyemail2after->username);
+
         $this->resetDebugging();
     }
 
index 347855f..b787dd8 100644 (file)
@@ -3,6 +3,7 @@ information provided here is intended especially for developers.
 
 === 3.0 ===
 
+* get_referer() has been deprecated, please use the get_local_referer function instead.
 * \core\progress\null is renamed to \core\progress\none for improved PHP7 compatibility as null is a reserved word (see MDL-50453).
 * \webservice_xmlrpc_client now respects proxy server settings. If your XMLRPC server is available on your local network and not via your proxy server, you may need to add it to the list of proxy
   server exceptions in $CFG->proxybypass. See MDL-39353 for details.
index 696caa5..bd3689b 100644 (file)
@@ -158,24 +158,6 @@ function strip_querystring($url) {
     }
 }
 
-/**
- * Returns the URL of the HTTP_REFERER, less the querystring portion if required.
- *
- * @param boolean $stripquery if true, also removes the query part of the url.
- * @return string The resulting referer or empty string.
- */
-function get_referer($stripquery=true) {
-    if (isset($_SERVER['HTTP_REFERER'])) {
-        if ($stripquery) {
-            return strip_querystring($_SERVER['HTTP_REFERER']);
-        } else {
-            return $_SERVER['HTTP_REFERER'];
-        }
-    } else {
-        return '';
-    }
-}
-
 /**
  * Returns the name of the current script, WITH the querystring portion.
  *
@@ -234,6 +216,25 @@ function is_https() {
     return (strpos($CFG->httpswwwroot, 'https://') === 0);
 }
 
+/**
+ * Returns the cleaned local URL of the HTTP_REFERER less the URL query string parameters if required.
+ *
+ * @param bool $stripquery if true, also removes the query part of the url.
+ * @return string The resulting referer or empty string.
+ */
+function get_local_referer($stripquery = true) {
+    if (isset($_SERVER['HTTP_REFERER'])) {
+        $referer = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+        if ($stripquery) {
+            return strip_querystring($referer);
+        } else {
+            return $referer;
+        }
+    } else {
+        return '';
+    }
+}
+
 /**
  * Class for creating and manipulating urls.
  *
index f610ce8..287d3da 100644 (file)
@@ -258,15 +258,16 @@ if ($session_has_timed_out and !data_submitted()) {
 /// First, let's remember where the user was trying to get to before they got here
 
 if (empty($SESSION->wantsurl)) {
-    $SESSION->wantsurl = (array_key_exists('HTTP_REFERER',$_SERVER) &&
-                          $_SERVER["HTTP_REFERER"] != $CFG->wwwroot &&
-                          $_SERVER["HTTP_REFERER"] != $CFG->wwwroot.'/' &&
-                          $_SERVER["HTTP_REFERER"] != $CFG->httpswwwroot.'/login/' &&
-                          strpos($_SERVER["HTTP_REFERER"], $CFG->httpswwwroot.'/login/?') !== 0 &&
-                          strpos($_SERVER["HTTP_REFERER"], $CFG->httpswwwroot.'/login/index.php') !== 0 &&
-                          clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL) != '')
-                          // There might be some extra params such as ?lang=.
-        ? $_SERVER["HTTP_REFERER"] : NULL;
+    $SESSION->wantsurl = null;
+    $referer = get_local_referer(false);
+    if ($referer &&
+            $referer != $CFG->wwwroot &&
+            $referer != $CFG->wwwroot . '/' &&
+            $referer != $CFG->httpswwwroot . '/login/' &&
+            strpos($referer, $CFG->httpswwwroot . '/login/?') !== 0 &&
+            strpos($referer, $CFG->httpswwwroot . '/login/index.php') !== 0) { // There might be some extra params such as ?lang=.
+        $SESSION->wantsurl = $referer;
+    }
 }
 
 /// Redirect to alternative login URL if needed
index f8c4a38..500db55 100644 (file)
@@ -178,7 +178,7 @@ if (!$choiceformshown) {
     } else if (!is_enrolled($context)) {
         // Only people enrolled can make a choice
         $SESSION->wantsurl = qualified_me();
-        $SESSION->enrolcancel = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+        $SESSION->enrolcancel = get_local_referer(false);
 
         $coursecontext = context_course::instance($course->id);
         $courseshortname = format_string($course->shortname, true, array('context' => $coursecontext));
index 0953d99..0742c85 100644 (file)
@@ -3930,7 +3930,7 @@ function forum_set_return() {
     global $CFG, $SESSION;
 
     if (! isset($SESSION->fromdiscussion)) {
-        $referer = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+        $referer = get_local_referer(false);
         // If the referer is NOT a login screen then save it.
         if (! strncasecmp("$CFG->wwwroot/login", $referer, 300)) {
             $SESSION->fromdiscussion = $referer;
index e6f2b33..1706c6a 100644 (file)
@@ -98,7 +98,7 @@ if ($mark == 'read') {
 //        if (forum_tp_start_tracking($forum->id, $user->id)) {
 //            redirect($returnto, get_string("nowtracking", "forum", $info), 1);
 //        } else {
-//            print_error("Could not start tracking that forum", $_SERVER["HTTP_REFERER"]);
+//            print_error("Could not start tracking that forum", get_local_referer());
 //        }
 }
 
index 2153cf6..bd6bc18 100644 (file)
@@ -53,7 +53,7 @@ $sitecontext = context_system::instance();
 
 if (!isloggedin() or isguestuser()) {
 
-    if (!isloggedin() and !get_referer()) {
+    if (!isloggedin() and !get_local_referer()) {
         // No referer+not logged in - probably coming in via email  See MDL-9052
         require_login();
     }
@@ -87,7 +87,7 @@ if (!isloggedin() or isguestuser()) {
     $PAGE->set_context($modcontext);
     $PAGE->set_title($course->shortname);
     $PAGE->set_heading($course->fullname);
-    $referer = clean_param(get_referer(false), PARAM_LOCALURL);
+    $referer = get_local_referer(false);
 
     echo $OUTPUT->header();
     echo $OUTPUT->confirm(get_string('noguestpost', 'forum').'<br /><br />'.get_string('liketologin'), get_login_url(), $referer);
@@ -117,7 +117,7 @@ if (!empty($forum)) {      // User is starting a new discussion in a forum
             if (!is_enrolled($coursecontext)) {
                 if (enrol_selfenrol_available($course->id)) {
                     $SESSION->wantsurl = qualified_me();
-                    $SESSION->enrolcancel = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+                    $SESSION->enrolcancel = get_local_referer(false);
                     redirect(new moodle_url('/enrol/index.php', array('id' => $course->id,
                         'returnurl' => '/mod/forum/view.php?f=' . $forum->id)),
                         get_string('youneedtoenrol'));
@@ -131,11 +131,7 @@ if (!empty($forum)) {      // User is starting a new discussion in a forum
         print_error("activityiscurrentlyhidden");
     }
 
-    if (isset($_SERVER["HTTP_REFERER"])) {
-        $SESSION->fromurl = $_SERVER["HTTP_REFERER"];
-    } else {
-        $SESSION->fromurl = '';
-    }
+    $SESSION->fromurl = get_local_referer(false);
 
     // Load up the $post variable.
 
@@ -188,7 +184,7 @@ if (!empty($forum)) {      // User is starting a new discussion in a forum
         if (!isguestuser()) {
             if (!is_enrolled($coursecontext)) {  // User is a guest here!
                 $SESSION->wantsurl = qualified_me();
-                $SESSION->enrolcancel = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+                $SESSION->enrolcancel = get_local_referer(false);
                 redirect(new moodle_url('/enrol/index.php', array('id' => $course->id,
                     'returnurl' => '/mod/forum/view.php?f=' . $forum->id)),
                     get_string('youneedtoenrol'));
index 004825f..ee062bc 100644 (file)
@@ -66,7 +66,7 @@ if (forum_tp_is_tracked($forum) ) {
         $event->trigger();
         redirect($returnto, get_string("nownottracking", "forum", $info), 1);
     } else {
-        print_error('cannottrack', '', $_SERVER["HTTP_REFERER"]);
+        print_error('cannottrack', '', get_local_referer(false));
     }
 
 } else { // subscribe
@@ -75,7 +75,7 @@ if (forum_tp_is_tracked($forum) ) {
         $event->trigger();
         redirect($returnto, get_string("nowtracking", "forum", $info), 1);
     } else {
-        print_error('cannottrack', '', $_SERVER["HTTP_REFERER"]);
+        print_error('cannottrack', '', get_local_referer(false));
     }
 }
 
index a18010c..7bd8414 100644 (file)
@@ -176,23 +176,23 @@ if ($issubscribed) {
         if (\mod_forum\subscriptions::unsubscribe_user($user->id, $forum, $context, true)) {
             redirect($returnto, get_string("nownotsubscribed", "forum", $info), 1);
         } else {
-            print_error('cannotunsubscribe', 'forum', $_SERVER["HTTP_REFERER"]);
+            print_error('cannotunsubscribe', 'forum', get_local_referer(false));
         }
     } else {
         if (\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion, $context)) {
             $info->discussion = $discussion->name;
             redirect($returnto, get_string("discussionnownotsubscribed", "forum", $info), 1);
         } else {
-            print_error('cannotunsubscribe', 'forum', $_SERVER["HTTP_REFERER"]);
+            print_error('cannotunsubscribe', 'forum', get_local_referer(false));
         }
     }
 
 } else {  // subscribe
     if (\mod_forum\subscriptions::subscription_disabled($forum) && !has_capability('mod/forum:managesubscriptions', $context)) {
-        print_error('disallowsubscribe', 'forum', $_SERVER["HTTP_REFERER"]);
+        print_error('disallowsubscribe', 'forum', get_local_referer(false));
     }
     if (!has_capability('mod/forum:viewdiscussion', $context)) {
-        print_error('noviewdiscussionspermission', 'forum', $_SERVER["HTTP_REFERER"]);
+        print_error('noviewdiscussionspermission', 'forum', get_local_referer(false));
     }
     if (is_null($sesskey)) {
         // We came here via link in email.
index 9772d45..b5173a2 100644 (file)
@@ -850,7 +850,7 @@ class mod_quiz_renderer extends plugin_renderer_base {
         $output .= $this->view_information($quiz, $cm, $context, $messages);
         $guestno = html_writer::tag('p', get_string('guestsno', 'quiz'));
         $liketologin = html_writer::tag('p', get_string('liketologin'));
-        $referer = clean_param(get_referer(false), PARAM_LOCALURL);
+        $referer = get_local_referer(false);
         $output .= $this->confirm($guestno."\n\n".$liketologin."\n", get_login_url(), $referer);
         return $output;
     }
index a409959..bc55f03 100644 (file)
@@ -89,7 +89,7 @@ if ($displaytype == RESOURCELIB_DISPLAY_OPEN || $displaytype == RESOURCELIB_DISP
     // For 'open' and 'download' links, we always redirect to the content - except
     // if the user just chose 'save and display' from the form then that would be
     // confusing
-    if (!isset($_SERVER['HTTP_REFERER']) || strpos($_SERVER['HTTP_REFERER'], 'modedit.php') === false) {
+    if (strpos(get_local_referer(false), 'modedit.php') === false) {
         $redirect = true;
     }
 }
index 0cf2613..a98013b 100644 (file)
@@ -70,7 +70,7 @@
     echo $OUTPUT->heading($survey->name);
 
     if (survey_already_done($survey->id, $USER->id)) {
-        notice(get_string("alreadysubmitted", "survey"), clean_param($_SERVER["HTTP_REFERER"], PARAM_LOCALURL));
+        notice(get_string("alreadysubmitted", "survey"), get_local_referer(false));
         exit;
     }
 
index 03ad747..4ca3131 100644 (file)
@@ -68,7 +68,7 @@ $displaytype = url_get_final_display_type($url);
 if ($displaytype == RESOURCELIB_DISPLAY_OPEN) {
     // For 'open' links, we always redirect to the content - except if the user
     // just chose 'save and display' from the form then that would be confusing
-    if (!isset($_SERVER['HTTP_REFERER']) || strpos($_SERVER['HTTP_REFERER'], 'modedit.php') === false) {
+    if (strpos(get_local_referer(false), 'modedit.php') === false) {
         $redirect = true;
     }
 }
index d890fe9..be2fd74 100644 (file)
@@ -60,7 +60,7 @@ if (!wiki_user_can_view($subwiki, $wiki)) {
 require_capability('mod/wiki:managefiles', $context);
 
 if (empty($returnurl)) {
-    $referer = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+    $referer = get_local_referer(false);
     if (!empty($referer)) {
         $returnurl = $referer;
     } else {
index 704d482..7cb63b7 100644 (file)
@@ -272,20 +272,18 @@ if (!empty($instanceid) && !empty($roleid)) {
 
     // Get record from sql_internal_table_reader and merge with records got from legacy log (if needed).
     if (!$onlyuselegacyreader) {
-        $sql = "SELECT ra.userid, $usernamefields, u.idnumber, COUNT(l.actioncount) AS count
-                  FROM (SELECT DISTINCT userid FROM {role_assignments} WHERE contextid $relatedctxsql AND roleid = :roleid ) ra
-                  JOIN {user} u ON u.id = ra.userid
+        $sql = "SELECT ra.userid, $usernamefields, u.idnumber, COUNT(DISTINCT l.timecreated) AS count
+                  FROM {user} u
+                  JOIN {role_assignments} ra ON u.id = ra.userid AND ra.contextid $relatedctxsql AND ra.roleid = :roleid
              $groupsql
-             LEFT JOIN (
-                    SELECT userid, COUNT(crud) AS actioncount
-                      FROM {" . $logtable . "}
-                     WHERE contextinstanceid = :instanceid
-                       AND timecreated > :timefrom" . $crudsql ."
-                       AND edulevel = :edulevel
-                       AND anonymous = 0
-                       AND contextlevel = :contextlevel
-                       AND (origin = 'web' OR origin = 'ws')
-                  GROUP BY userid,timecreated) l ON (l.userid = ra.userid)";
+                  LEFT JOIN {" . $logtable . "} l
+                     ON l.contextinstanceid = :instanceid
+                       AND l.timecreated > :timefrom" . $crudsql ."
+                       AND l.edulevel = :edulevel
+                       AND l.anonymous = 0
+                       AND l.contextlevel = :contextlevel
+                       AND (l.origin = 'web' OR l.origin = 'ws')
+                       AND l.userid = ra.userid";
         // We add this after the WHERE statement that may come below.
         $groupbysql = " GROUP BY ra.userid, $usernamefields, u.idnumber";
 
index 05837e8..d306425 100644 (file)
@@ -69,13 +69,13 @@ class manager {
         }
 
         // Plugins.
-        $types = \core_component::get_plugin_types();
-        foreach ($types as $type => $dir) {
-            $pluginlist = get_plugin_list_with_function($type, "myprofile_navigation", "lib.php");
-            foreach ($pluginlist as $function) {
+        $pluginswithfunction = get_plugins_with_function('myprofile_navigation', 'lib.php');
+        foreach ($pluginswithfunction as $plugins) {
+            foreach ($plugins as $function) {
                 $function($tree, $user, $iscurrentuser, $course);
             }
         }
+
         $tree->sort_categories();
         return $tree;
     }
index 80711c7..f2cdcd6 100644 (file)
@@ -112,7 +112,7 @@ if ($currentuser) {
         // Need to have full access to a course to see the rest of own info.
         echo $OUTPUT->header();
         echo $OUTPUT->heading(get_string('notenrolled', '', $fullname));
-        $referer = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+        $referer = get_local_referer(false);
         if (!empty($referer)) {
             echo $OUTPUT->continue_button($referer);
         }
@@ -144,7 +144,7 @@ if ($currentuser) {
             $PAGE->navbar->add($struser);
             echo $OUTPUT->heading(get_string('notenrolledprofile'));
         }
-        $referer = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+        $referer = get_local_referer(false);
         if (!empty($referer)) {
             echo $OUTPUT->continue_button($referer);
         }
index 8cd33c1..ec77c35 100644 (file)
@@ -29,7 +29,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$version  = 2015072300.00;              // YYYYMMDD      = weekly release date of this DEV branch.
+$version  = 2015072700.00;              // YYYYMMDD      = weekly release date of this DEV branch.
                                         //         RR    = release increments - 00 in DEV branches.
                                         //           .XX = incremental changes.