1<?php 2 3/** 4 * Moodle - Modular Object-Oriented Dynamic Learning Environment 5 * http://moodle.org 6 * Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation, either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 * 21 * @package moodle 22 * @subpackage lib 23 * @author Dan Poltawski <talktodan@gmail.com> 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 * 26 * Customised version of SimplePie for Moodle 27 */ 28 29require_once($CFG->libdir.'/filelib.php'); 30 31// PLEASE NOTE: we use the simplepie class _unmodified_ 32// through the joys of OO. Distros are free to use their stock 33// version of this file. 34require_once($CFG->libdir.'/simplepie/autoloader.php'); 35 36/** 37 * Moodle Customised version of the SimplePie class 38 * 39 * This class extends the stock SimplePie class 40 * in order to make sensible configuration choices, 41 * such as using the Moodle cache directory and 42 * curl functions/proxy config for making http 43 * requests in line with moodle configuration. 44 * 45 * @copyright 2009 Dan Poltawski <talktodan@gmail.com> 46 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 47 * @since Moodle 2.0 48 */ 49class moodle_simplepie extends SimplePie { 50 /** 51 * Constructor - creates an instance of the SimplePie class 52 * with Moodle defaults. 53 * 54 * @param string $feedurl optional URL of the feed 55 * @param int $timeout how many seconds requests should wait for server response 56 */ 57 public function __construct($feedurl = null, $timeout = 2) { 58 $cachedir = moodle_simplepie::get_cache_directory(); 59 check_dir_exists($cachedir); 60 61 parent::__construct(); 62 63 // Use the Moodle class for http requests 64 $this->set_file_class('moodle_simplepie_file'); 65 66 // Use html purifier for text cleaning. 67 $this->set_sanitize_class('moodle_simplepie_sanitize'); 68 $this->sanitize = new moodle_simplepie_sanitize(); 69 70 // Match moodle encoding 71 $this->set_output_encoding('UTF-8'); 72 73 // default to a short timeout as most operations will be interactive 74 $this->set_timeout($timeout); 75 76 // 1 hour default cache 77 $this->set_cache_location($cachedir); 78 $this->set_cache_duration(3600); 79 80 // init the feed url if passed in constructor 81 if ($feedurl !== null) { 82 $this->set_feed_url($feedurl); 83 $this->init(); 84 } 85 } 86 87 /** 88 * Get path for feed cache directory 89 * 90 * @return string absolute path to cache directory 91 */ 92 private static function get_cache_directory() { 93 global $CFG; 94 95 return $CFG->cachedir.'/simplepie/'; 96 } 97 98 /** 99 * Reset RSS cache 100 * 101 * @return boolean success if cache clear or didn't exist 102 */ 103 public static function reset_cache() { 104 105 $cachedir = moodle_simplepie::get_cache_directory(); 106 107 return remove_dir($cachedir); 108 } 109} 110 111/** 112 * Moodle Customised version of the SimplePie_File class 113 * 114 * This class extends the stock SimplePie class 115 * in order to utilise Moodles own curl class for making 116 * http requests. By using the moodle curl class 117 * we ensure that the correct proxy configuration is used. 118 */ 119class moodle_simplepie_file extends SimplePie_File { 120 121 /** 122 * The constructor is a copy of the stock simplepie File class which has 123 * been modified to add in use the Moodle curl class rather than php curl 124 * functions. 125 */ 126 public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) { 127 $this->url = $url; 128 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL; 129 130 $curl = new curl(); 131 $curl->setopt( array( 132 'CURLOPT_HEADER' => true, 133 'CURLOPT_TIMEOUT' => $timeout, 134 'CURLOPT_CONNECTTIMEOUT' => $timeout )); 135 136 137 if ($headers !== null) { 138 // translate simplepie headers to those class curl expects 139 foreach($headers as $headername => $headervalue){ 140 $headerstr = "{$headername}: {$headervalue}"; 141 $curl->setHeader($headerstr); 142 } 143 } 144 145 $this->headers = curl::strip_double_headers($curl->get($url)); 146 147 if ($curl->error) { 148 $this->error = 'cURL Error: '.$curl->error; 149 $this->success = false; 150 return false; 151 } 152 153 $parser = new SimplePie_HTTP_Parser($this->headers); 154 155 if ($parser->parse()) { 156 $this->headers = $parser->headers; 157 $this->body = trim($parser->body); 158 $this->status_code = $parser->status_code; 159 160 161 if (($this->status_code == 300 || $this->status_code == 301 || $this->status_code == 302 || $this->status_code == 303 162 || $this->status_code == 307 || $this->status_code > 307 && $this->status_code < 400) 163 && isset($this->headers['location']) && $this->redirects < $redirects) { 164 $this->redirects++; 165 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url); 166 return $this->__construct($location, $timeout, $redirects, $headers); 167 } 168 } 169 } 170} 171 172 173/** 174 * Customised feed sanitization using HTMLPurifier. 175 */ 176class moodle_simplepie_sanitize extends SimplePie_Sanitize { 177 public function sanitize($data, $type, $base = '') { 178 $data = trim($data); 179 180 if ($data === '') { 181 return ''; 182 } 183 184 if ($type & SIMPLEPIE_CONSTRUCT_BASE64){ 185 $data = base64_decode($data); 186 } 187 188 if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML) { 189 if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data)) { 190 $type |= SIMPLEPIE_CONSTRUCT_HTML; 191 } else { 192 $type |= SIMPLEPIE_CONSTRUCT_TEXT; 193 } 194 } 195 196 if ($type & SIMPLEPIE_CONSTRUCT_IRI) { 197 $absolute = $this->registry->call('Misc', 'absolutize_url', array($data, $base)); 198 if ($absolute !== false) { 199 $data = $absolute; 200 } 201 $data = clean_param($data, PARAM_URL); 202 } 203 204 if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI)) { 205 $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8'); 206 } 207 208 $data = purify_html($data); 209 210 if ($this->remove_div) { 211 $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data); 212 $data = preg_replace('/<\/div>$/', '', $data); 213 } else { 214 $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data); 215 } 216 217 if ($this->output_encoding !== 'UTF-8') { 218 core_text::convert($data, 'UTF-8', $this->output_encoding); 219 } 220 221 return $data; 222 } 223} 224