See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]
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/>. 16 17 /** 18 * Manager for media files 19 * 20 * @package core_media 21 * @copyright 2016 Marina Glancy 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 27 /** 28 * Manager for media files. 29 * 30 * Used in file resources, media filter, and any other places that need to 31 * output embedded media. 32 * 33 * Usage: 34 * $manager = core_media_manager::instance(); 35 * 36 * 37 * @package core_media 38 * @copyright 2016 Marina Glancy 39 * @author 2011 The Open University 40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 41 */ 42 final class core_media_manager { 43 /** 44 * Option: Disable text link fallback. 45 * 46 * Use this option if you are going to print a visible link anyway so it is 47 * pointless to have one as fallback. 48 * 49 * To enable, set value to true. 50 */ 51 const OPTION_NO_LINK = 'nolink'; 52 53 /** 54 * Option: When embedding, if there is no matching embed, do not use the 55 * default link fallback player; instead return blank. 56 * 57 * This is different from OPTION_NO_LINK because this option still uses the 58 * fallback link if there is some kind of embedding. Use this option if you 59 * are going to check if the return value is blank and handle it specially. 60 * 61 * To enable, set value to true. 62 */ 63 const OPTION_FALLBACK_TO_BLANK = 'embedorblank'; 64 65 /** 66 * Option: Enable players which are only suitable for use when we trust the 67 * user who embedded the content. 68 * 69 * At present, this option enables the SWF player. 70 * 71 * To enable, set value to true. 72 */ 73 const OPTION_TRUSTED = 'trusted'; 74 75 /** 76 * Option: Put a div around the output (if not blank) so that it displays 77 * as a block using the 'resourcecontent' CSS class. 78 * 79 * To enable, set value to true. 80 */ 81 const OPTION_BLOCK = 'block'; 82 83 /** 84 * Option: When the request for media players came from a text filter this option will contain the 85 * original HTML snippet, usually one of the tags: <a> or <video> or <audio> 86 * 87 * Players that support other HTML5 features such as tracks may find them in this option. 88 */ 89 const OPTION_ORIGINAL_TEXT = 'originaltext'; 90 91 /** @var array Array of available 'player' objects */ 92 private $players; 93 94 /** @var string Regex pattern for links which may contain embeddable content */ 95 private $embeddablemarkers; 96 97 /** @var core_media_manager caches a singleton instance */ 98 static private $instance; 99 100 /** @var moodle_page page this instance was initialised for */ 101 private $page; 102 103 /** 104 * Returns a singleton instance of a manager 105 * 106 * Note as of Moodle 3.3, this will call setup for you. 107 * 108 * @return core_media_manager 109 */ 110 public static function instance($page = null) { 111 // Use the passed $page if given, otherwise the $PAGE global. 112 if (!$page) { 113 global $PAGE; 114 $page = $PAGE; 115 } 116 if (self::$instance === null || ($page && self::$instance->page !== $page)) { 117 self::$instance = new self($page); 118 } 119 return self::$instance; 120 } 121 122 /** 123 * Construct a new core_media_manager instance 124 * 125 * @param moodle_page $page The page we are going to add requirements to. 126 * @see core_media_manager::instance() 127 */ 128 private function __construct($page) { 129 if ($page) { 130 $this->page = $page; 131 $players = $this->get_players(); 132 foreach ($players as $player) { 133 $player->setup($page); 134 } 135 } else { 136 debugging('Could not determine the $PAGE. Media plugins will not be set up', DEBUG_DEVELOPER); 137 } 138 } 139 140 /** 141 * @deprecated since Moodle 3.3. The setup is now done in ::instance() so there is no need to call this. 142 */ 143 public function setup() { 144 throw new coding_exception('core_media_manager::setup() can not be used any more because it is done in ::instance()'); 145 } 146 147 /** 148 * Resets cached singleton instance. To be used after $CFG->media_plugins_sortorder is modified 149 */ 150 public static function reset_caches() { 151 self::$instance = null; 152 } 153 154 /** 155 * Obtains the list of core_media_player objects currently in use to render 156 * items. 157 * 158 * The list is in rank order (highest first) and does not include players 159 * which are disabled. 160 * 161 * @return core_media_player[] Array of core_media_player objects in rank order 162 */ 163 private function get_players() { 164 // Save time by only building the list once. 165 if (!$this->players) { 166 $sortorder = \core\plugininfo\media::get_enabled_plugins(); 167 168 $this->players = []; 169 foreach ($sortorder as $name) { 170 $classname = "media_" . $name . "_plugin"; 171 if (class_exists($classname)) { 172 $this->players[] = new $classname(); 173 } 174 } 175 } 176 return $this->players; 177 } 178 179 /** 180 * Renders a media file (audio or video) using suitable embedded player. 181 * 182 * See embed_alternatives function for full description of parameters. 183 * This function calls through to that one. 184 * 185 * When using this function you can also specify width and height in the 186 * URL by including ?d=100x100 at the end. If specified in the URL, this 187 * will override the $width and $height parameters. 188 * 189 * @param moodle_url $url Full URL of media file 190 * @param string $name Optional user-readable name to display in download link 191 * @param int $width Width in pixels (optional) 192 * @param int $height Height in pixels (optional) 193 * @param array $options Array of key/value pairs 194 * @return string HTML content of embed 195 */ 196 public function embed_url(moodle_url $url, $name = '', $width = 0, $height = 0, 197 $options = array()) { 198 199 // Get width and height from URL if specified (overrides parameters in 200 // function call). 201 $rawurl = $url->out(false); 202 if (preg_match('/[?#]d=([\d]{1,4}%?)x([\d]{1,4}%?)/', $rawurl, $matches)) { 203 $width = $matches[1]; 204 $height = $matches[2]; 205 $url = new moodle_url(str_replace($matches[0], '', $rawurl)); 206 } 207 208 // Defer to array version of function. 209 return $this->embed_alternatives(array($url), $name, $width, $height, $options); 210 } 211 212 /** 213 * Renders media files (audio or video) using suitable embedded player. 214 * The list of URLs should be alternative versions of the same content in 215 * multiple formats. If there is only one format it should have a single 216 * entry. 217 * 218 * If the media files are not in a supported format, this will give students 219 * a download link to each format. The download link uses the filename 220 * unless you supply the optional name parameter. 221 * 222 * Width and height are optional. If specified, these are suggested sizes 223 * and should be the exact values supplied by the user, if they come from 224 * user input. These will be treated as relating to the size of the video 225 * content, not including any player control bar. 226 * 227 * For audio files, height will be ignored. For video files, a few formats 228 * work if you specify only width, but in general if you specify width 229 * you must specify height as well. 230 * 231 * The $options array is passed through to the core_media_player classes 232 * that render the object tag. The keys can contain values from 233 * core_media::OPTION_xx. 234 * 235 * @param array $alternatives Array of moodle_url to media files 236 * @param string $name Optional user-readable name to display in download link 237 * @param int $width Width in pixels (optional) 238 * @param int $height Height in pixels (optional) 239 * @param array $options Array of key/value pairs 240 * @return string HTML content of embed 241 */ 242 public function embed_alternatives($alternatives, $name = '', $width = 0, $height = 0, 243 $options = array()) { 244 245 // Get list of player plugins. 246 $players = $this->get_players(); 247 248 // Set up initial text which will be replaced by first player that 249 // supports any of the formats. 250 $out = core_media_player::PLACEHOLDER; 251 252 // Loop through all players that support any of these URLs. 253 foreach ($players as $player) { 254 $supported = $player->list_supported_urls($alternatives, $options); 255 if ($supported) { 256 // Embed. 257 $text = $player->embed($supported, $name, $width, $height, $options); 258 259 // Put this in place of the 'fallback' slot in the previous text. 260 $out = str_replace(core_media_player::PLACEHOLDER, $text, $out); 261 262 // Check if we need to continue looking for players. 263 if (strpos($out, core_media_player::PLACEHOLDER) === false) { 264 break; 265 } 266 } 267 } 268 269 if (!empty($options[self::OPTION_FALLBACK_TO_BLANK]) && $out === core_media_player::PLACEHOLDER) { 270 // In case of OPTION_FALLBACK_TO_BLANK and no player matched do not fallback to link, just return empty string. 271 return ''; 272 } 273 274 // Remove 'fallback' slot from final version and return it. 275 $fallback = $this->fallback_to_link($alternatives, $name, $options); 276 $out = str_replace(core_media_player::PLACEHOLDER, $fallback, $out); 277 $out = str_replace(core_media_player::LINKPLACEHOLDER, $fallback, $out); 278 if (!empty($options[self::OPTION_BLOCK]) && $out !== '') { 279 $out = html_writer::tag('div', $out, array('class' => 'resourcecontent')); 280 } 281 return $out; 282 } 283 284 /** 285 * Returns links to the specified URLs unless OPTION_NO_LINK is passed. 286 * 287 * @param array $urls URLs of media files 288 * @param string $name Display name; '' to use default 289 * @param array $options Options array 290 * @return string HTML code for embed 291 */ 292 private function fallback_to_link($urls, $name, $options) { 293 // If link is turned off, return empty. 294 if (!empty($options[self::OPTION_NO_LINK])) { 295 return ''; 296 } 297 298 // Build up link content. 299 $output = ''; 300 foreach ($urls as $url) { 301 if (strval($name) !== '' && $output === '') { 302 $title = $name; 303 } else { 304 $title = $this->get_filename($url); 305 } 306 $printlink = html_writer::link($url, $title, array('class' => 'mediafallbacklink')); 307 if ($output) { 308 // Where there are multiple available formats, there are fallback links 309 // for all formats, separated by /. 310 $output .= ' / '; 311 } 312 $output .= $printlink; 313 } 314 return $output; 315 } 316 317 /** 318 * Checks whether a file can be embedded. If this returns true you will get 319 * an embedded player; if this returns false, you will just get a download 320 * link. 321 * 322 * This is a wrapper for can_embed_urls. 323 * 324 * @param moodle_url $url URL of media file 325 * @param array $options Options (same as when embedding) 326 * @return bool True if file can be embedded 327 */ 328 public function can_embed_url(moodle_url $url, $options = array()) { 329 return $this->can_embed_urls(array($url), $options); 330 } 331 332 /** 333 * Checks whether a file can be embedded. If this returns true you will get 334 * an embedded player; if this returns false, you will just get a download 335 * link. 336 * 337 * @param array $urls URL of media file and any alternatives (moodle_url) 338 * @param array $options Options (same as when embedding) 339 * @return bool True if file can be embedded 340 */ 341 public function can_embed_urls(array $urls, $options = array()) { 342 // Check all players to see if any of them support it. 343 foreach ($this->get_players() as $player) { 344 // First player that supports it, return true. 345 if ($player->list_supported_urls($urls, $options)) { 346 return true; 347 } 348 } 349 return false; 350 } 351 352 /** 353 * Obtains a list of markers that can be used in a regular expression when 354 * searching for URLs that can be embedded by any player type. 355 * 356 * This string is used to improve peformance of regex matching by ensuring 357 * that the (presumably C) regex code can do a quick keyword check on the 358 * URL part of a link to see if it matches one of these, rather than having 359 * to go into PHP code for every single link to see if it can be embedded. 360 * 361 * @return string String suitable for use in regex such as '(\.mp4|\.flv)' 362 */ 363 public function get_embeddable_markers() { 364 if (empty($this->embeddablemarkers)) { 365 $markers = ''; 366 foreach ($this->get_players() as $player) { 367 foreach ($player->get_embeddable_markers() as $marker) { 368 if ($markers !== '') { 369 $markers .= '|'; 370 } 371 $markers .= preg_quote($marker); 372 } 373 } 374 $this->embeddablemarkers = $markers; 375 } 376 return $this->embeddablemarkers; 377 } 378 379 /** 380 * Given a string containing multiple URLs separated by #, this will split 381 * it into an array of moodle_url objects suitable for using when calling 382 * embed_alternatives. 383 * 384 * Note that the input string should NOT be html-escaped (i.e. if it comes 385 * from html, call html_entity_decode first). 386 * 387 * @param string $combinedurl String of 1 or more alternatives separated by # 388 * @param int $width Output variable: width (will be set to 0 if not specified) 389 * @param int $height Output variable: height (0 if not specified) 390 * @return array Array of 1 or more moodle_url objects 391 */ 392 public function split_alternatives($combinedurl, &$width, &$height) { 393 global $CFG; 394 $urls = explode('#', $combinedurl); 395 $width = 0; 396 $height = 0; 397 $returnurls = array(); 398 399 foreach ($urls as $url) { 400 $matches = null; 401 402 // You can specify the size as a separate part of the array like 403 // #d=640x480 without actually including a url in it. 404 if (preg_match('/^d=([\d]{1,4})x([\d]{1,4})$/i', $url, $matches)) { 405 $width = $matches[1]; 406 $height = $matches[2]; 407 continue; 408 } 409 410 // Can also include the ?d= as part of one of the URLs (if you use 411 // more than one they will be ignored except the last). 412 if (preg_match('/\?d=([\d]{1,4})x([\d]{1,4})$/i', $url, $matches)) { 413 $width = $matches[1]; 414 $height = $matches[2]; 415 416 // Trim from URL. 417 $url = str_replace($matches[0], '', $url); 418 } 419 420 // Clean up url. 421 $url = fix_utf8($url); 422 include_once($CFG->dirroot . '/lib/validateurlsyntax.php'); 423 if (!validateUrlSyntax($url, 's?H?S?F?R?E?u-P-a?I?p?f?q?r?')) { 424 continue; 425 } 426 427 // Turn it into moodle_url object. 428 $returnurls[] = new moodle_url($url); 429 } 430 431 return $returnurls; 432 } 433 434 /** 435 * Returns the file extension for a URL. 436 * @param moodle_url $url URL 437 */ 438 public function get_extension(moodle_url $url) { 439 // Note: Does not use core_text (. is UTF8-safe). 440 $filename = self::get_filename($url); 441 $dot = strrpos($filename, '.'); 442 if ($dot === false) { 443 return ''; 444 } else { 445 return strtolower(substr($filename, $dot + 1)); 446 } 447 } 448 449 /** 450 * Obtains the filename from the moodle_url. 451 * @param moodle_url $url URL 452 * @return string Filename only (not escaped) 453 */ 454 public function get_filename(moodle_url $url) { 455 // Use the 'file' parameter if provided (for links created when 456 // slasharguments was off). If not present, just use URL path. 457 $path = $url->get_param('file'); 458 if (!$path) { 459 $path = $url->get_path(); 460 } 461 462 // Remove everything before last / if present. Does not use textlib as / is UTF8-safe. 463 $slash = strrpos($path, '/'); 464 if ($slash !== false) { 465 $path = substr($path, $slash + 1); 466 } 467 return $path; 468 } 469 470 /** 471 * Guesses MIME type for a moodle_url based on file extension. 472 * @param moodle_url $url URL 473 * @return string MIME type 474 */ 475 public function get_mimetype(moodle_url $url) { 476 return mimeinfo('type', $this->get_filename($url)); 477 } 478 479 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body