Merge branch 'MDL-62268-master' of git://github.com/bmbrands/moodle
[moodle.git] / rss / file.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * rss/file.php - entry point to serve rss streams
19  *
20  * This script simply checks the parameters to construct a $USER
21  * then finds and calls a function in the relevant component to
22  * actually check security and create the RSS stream
23  *
24  * @package    core_rss
25  * @category   rss
26  * @copyright  1999 onwards Martin Dougiamas {@link http://moodle.com}
27  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28  */
30 /** NO_DEBUG_DISPLAY - bool, Disable moodle debug and error messages. Set to false to see any errors during RSS generation */
31 define('NO_DEBUG_DISPLAY', true);
33 /** NO_MOODLE_COOKIES - bool, Disable the use of sessions/cookies - we recreate $USER for every call. */
34 define('NO_MOODLE_COOKIES', true);
36 require_once('../config.php');
37 require_once($CFG->libdir.'/filelib.php');
38 require_once($CFG->libdir.'/rsslib.php');
40 // RSS feeds must be enabled site-wide.
41 if (empty($CFG->enablerssfeeds)) {
42     rss_error();
43 }
45 // All the arguments are in the path.
46 $relativepath = get_file_argument();
47 if (!$relativepath) {
48     rss_error();
49 }
51 // Extract relative path components into variables.
52 $args = explode('/', trim($relativepath, '/'));
53 if (count($args) < 5) {
54     rss_error();
55 }
57 $contextid   = (int)$args[0];
58 $token  = clean_param($args[1], PARAM_ALPHANUM);
59 $componentname = clean_param($args[2], PARAM_FILE);
61 // Check if they have requested a 1.9 RSS feed.
62 // If token is an int it is a user id (1.9 request).
63 // If token contains any letters it is a token (2.0 request).
64 $inttoken = intval($token);
65 if ($token === "$inttoken") {
66     // They have requested a feed using a 1.9 url. redirect them to the 2.0 url using the guest account.
68     $instanceid  = clean_param($args[3], PARAM_INT);
70     // 1.9 URL puts course id where the context id is in 2.0 URLs.
71     $courseid = $contextid;
72     unset($contextid);
74     // Find the context id.
75     if ($course = $DB->get_record('course', array('id' => $courseid))) {
76         $modinfo = get_fast_modinfo($course);
78         foreach ($modinfo->get_instances_of($componentname) as $modinstanceid => $cm) {
79             if ($modinstanceid == $instanceid) {
80                 $context = context_module::instance($cm->id, IGNORE_MISSING);
81                 break;
82             }
83         }
84     }
86     if (empty($context)) {
87         // This shouldnt happen. something bad is going on.
88         rss_error();
89     }
91     // Make sure that $CFG->siteguest is set.
92     if (empty($CFG->siteguest)) {
93         if (!$guestid = $DB->get_field('user', 'id', array('username' => 'guest', 'mnethostid' => $CFG->mnet_localhost_id))) {
94             // Guest does not exist yet, weird.
95             rss_error();
96         }
97         set_config('siteguest', $guestid);
98     }
99     $guesttoken = rss_get_token($CFG->siteguest);
101     // Change forum to mod_forum (for example).
102     $componentname = 'mod_'.$componentname;
104     $url = $PAGE->url;
105     $url->set_slashargument("/{$context->id}/$guesttoken/$componentname/$instanceid/rss.xml");
107     // Redirect to the 2.0 rss URL.
108     redirect($url);
109 } else {
110     // Authenticate the user from the token.
111     $userid = rss_get_userid_from_token($token);
112     if (!$userid) {
113         rss_error('rsserrorauth', 'rss.xml', 0, '403 Forbidden');
114     }
117 // Check the context actually exists.
118 try {
119     list($context, $course, $cm) = get_context_info_array($contextid);
120 } catch (dml_missing_record_exception $e) {
121     rss_error();
124 $PAGE->set_context($context);
126 $user = get_complete_user_data('id', $userid);
128 // Let enrol plugins deal with new enrolments if necessary.
129 enrol_check_plugins($user);
131 \core\session\manager::set_user($user); // For login and capability checks.
133 try {
134     $autologinguest = true;
135     $setwantsurltome = true;
136     $preventredirect = true;
137     require_course_login($course, $autologinguest, $cm, $setwantsurltome, $preventredirect);
138 } catch (Exception $e) {
139     if (isguestuser()) {
140         rss_error('rsserrorguest', 'rss.xml', 0, '403 Forbidden');
141     } else {
142         rss_error('rsserrorauth', 'rss.xml', 0, '403 Forbidden');
143     }
146 // Work out which component in Moodle we want (from the frankenstyle name).
147 $componentdir = core_component::get_component_directory($componentname);
148 list($type, $plugin) = core_component::normalize_component($componentname);
150 // Call the component to check/update the feed and tell us the path to the cached file.
151 $pathname = null;
153 if (file_exists($componentdir)) {
154     require_once("$componentdir/rsslib.php");
155     $functionname = $plugin.'_rss_get_feed';
157     if (function_exists($functionname)) {
158         // The $pathname will be null if there was a problem (eg user doesn't have the necessary capabilities).
159         // NOTE:the component providing the feed must do its own capability checks and security.
160         try {
161             $pathname = $functionname($context, $args);
162         } catch (Exception $e) {
163             rss_error('rsserror');
164         }
165     }
168 // Check that file exists.
169 if (empty($pathname) || !file_exists($pathname)) {
170     rss_error();
173 // Send the RSS file to the user!
174 send_file($pathname, 'rss.xml', 3600);   // Cached by browsers for 1 hour.
176 /**
177  * Sends an error formatted as an rss file and then exits
178  *
179  * @package core_rss
180  * @category rss
181  *
182  * @param string $error the error type, default is rsserror
183  * @param string $filename the name of the file to created
184  * @param int $unused
185  * @param string $statuscode http 1.1 statuscode indicicating the error
186  * @uses exit
187  */
188 function rss_error($error='rsserror', $filename='rss.xml', $unused=0, $statuscode='404 Not Found') {
189     header("HTTP/1.1 $statuscode");
190     header('Content-Disposition: inline; filename="'.$filename.'"');
191     header('Content-Type: application/xml');
192     echo rss_geterrorxmlfile($error);
193     exit;