[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 * Classes for handling embedded media (mainly audio and video). 19 * 20 * These are used only from within the core media renderer. 21 * 22 * To embed media from Moodle code, do something like the following: 23 * 24 * $mediarenderer = $PAGE->get_renderer('core', 'media'); 25 * echo $mediarenderer->embed_url(new moodle_url('http://example.org/a.mp3')); 26 * 27 * You do not need to require this library file manually. Getting the renderer 28 * (the first line above) requires this library file automatically. 29 * 30 * @package core_media 31 * @copyright 2012 The Open University 32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 */ 34 35 defined('MOODLE_INTERNAL') || die(); 36 37 if (!defined('CORE_MEDIA_VIDEO_WIDTH')) { 38 // Default video width if no width is specified; some players may do something 39 // more intelligent such as use real video width. 40 // May be defined in config.php if required. 41 define('CORE_MEDIA_VIDEO_WIDTH', 400); 42 } 43 if (!defined('CORE_MEDIA_VIDEO_HEIGHT')) { 44 // Default video height. May be defined in config.php if required. 45 define('CORE_MEDIA_VIDEO_HEIGHT', 300); 46 } 47 if (!defined('CORE_MEDIA_AUDIO_WIDTH')) { 48 // Default audio width if no width is specified. 49 // May be defined in config.php if required. 50 define('CORE_MEDIA_AUDIO_WIDTH', 300); 51 } 52 53 54 /** 55 * Constants and static utility functions for use with core_media_renderer. 56 * 57 * @copyright 2011 The Open University 58 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 59 */ 60 abstract class core_media { 61 /** 62 * Option: Disable text link fallback. 63 * 64 * Use this option if you are going to print a visible link anyway so it is 65 * pointless to have one as fallback. 66 * 67 * To enable, set value to true. 68 */ 69 const OPTION_NO_LINK = 'nolink'; 70 71 /** 72 * Option: When embedding, if there is no matching embed, do not use the 73 * default link fallback player; instead return blank. 74 * 75 * This is different from OPTION_NO_LINK because this option still uses the 76 * fallback link if there is some kind of embedding. Use this option if you 77 * are going to check if the return value is blank and handle it specially. 78 * 79 * To enable, set value to true. 80 */ 81 const OPTION_FALLBACK_TO_BLANK = 'embedorblank'; 82 83 /** 84 * Option: Enable players which are only suitable for use when we trust the 85 * user who embedded the content. 86 * 87 * At present, this option enables the SWF player. 88 * 89 * To enable, set value to true. 90 */ 91 const OPTION_TRUSTED = 'trusted'; 92 93 /** 94 * Option: Put a div around the output (if not blank) so that it displays 95 * as a block using the 'resourcecontent' CSS class. 96 * 97 * To enable, set value to true. 98 */ 99 const OPTION_BLOCK = 'block'; 100 101 /** 102 * Given a string containing multiple URLs separated by #, this will split 103 * it into an array of moodle_url objects suitable for using when calling 104 * embed_alternatives. 105 * 106 * Note that the input string should NOT be html-escaped (i.e. if it comes 107 * from html, call html_entity_decode first). 108 * 109 * @param string $combinedurl String of 1 or more alternatives separated by # 110 * @param int $width Output variable: width (will be set to 0 if not specified) 111 * @param int $height Output variable: height (0 if not specified) 112 * @return array Array of 1 or more moodle_url objects 113 */ 114 public static function split_alternatives($combinedurl, &$width, &$height) { 115 $urls = explode('#', $combinedurl); 116 $width = 0; 117 $height = 0; 118 $returnurls = array(); 119 120 foreach ($urls as $url) { 121 $matches = null; 122 123 // You can specify the size as a separate part of the array like 124 // #d=640x480 without actually including a url in it. 125 if (preg_match('/^d=([\d]{1,4})x([\d]{1,4})$/i', $url, $matches)) { 126 $width = $matches[1]; 127 $height = $matches[2]; 128 continue; 129 } 130 131 // Can also include the ?d= as part of one of the URLs (if you use 132 // more than one they will be ignored except the last). 133 if (preg_match('/\?d=([\d]{1,4})x([\d]{1,4})$/i', $url, $matches)) { 134 $width = $matches[1]; 135 $height = $matches[2]; 136 137 // Trim from URL. 138 $url = str_replace($matches[0], '', $url); 139 } 140 141 // Clean up url. 142 $url = clean_param($url, PARAM_URL); 143 if (empty($url)) { 144 continue; 145 } 146 147 // Turn it into moodle_url object. 148 $returnurls[] = new moodle_url($url); 149 } 150 151 return $returnurls; 152 } 153 154 /** 155 * Returns the file extension for a URL. 156 * @param moodle_url $url URL 157 */ 158 public static function get_extension(moodle_url $url) { 159 // Note: Does not use core_text (. is UTF8-safe). 160 $filename = self::get_filename($url); 161 $dot = strrpos($filename, '.'); 162 if ($dot === false) { 163 return ''; 164 } else { 165 return strtolower(substr($filename, $dot + 1)); 166 } 167 } 168 169 /** 170 * Obtains the filename from the moodle_url. 171 * @param moodle_url $url URL 172 * @return string Filename only (not escaped) 173 */ 174 public static function get_filename(moodle_url $url) { 175 global $CFG; 176 177 // Use the 'file' parameter if provided (for links created when 178 // slasharguments was off). If not present, just use URL path. 179 $path = $url->get_param('file'); 180 if (!$path) { 181 $path = $url->get_path(); 182 } 183 184 // Remove everything before last / if present. Does not use textlib as / is UTF8-safe. 185 $slash = strrpos($path, '/'); 186 if ($slash !== false) { 187 $path = substr($path, $slash + 1); 188 } 189 return $path; 190 } 191 192 /** 193 * Guesses MIME type for a moodle_url based on file extension. 194 * @param moodle_url $url URL 195 * @return string MIME type 196 */ 197 public static function get_mimetype(moodle_url $url) { 198 return mimeinfo('type', self::get_filename($url)); 199 } 200 } 201 202 203 /** 204 * Base class for media players. 205 * 206 * Media players return embed HTML for a particular way of playing back audio 207 * or video (or another file type). 208 * 209 * In order to make the code more lightweight, this is not a plugin type 210 * (players cannot have their own settings, database tables, capabilities, etc). 211 * These classes are used only by core_media_renderer in outputrenderers.php. 212 * If you add a new class here (in core code) you must modify the 213 * get_players_raw function in that file to include it. 214 * 215 * If a Moodle installation wishes to add extra player objects they can do so 216 * by overriding that renderer in theme, and overriding the get_players_raw 217 * function. The new player class should then of course be defined within the 218 * custom theme or other suitable location, not in this file. 219 * 220 * @copyright 2011 The Open University 221 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 222 */ 223 abstract class core_media_player { 224 /** 225 * Placeholder text used to indicate where the fallback content is placed 226 * within a result. 227 */ 228 const PLACEHOLDER = '<!--FALLBACK-->'; 229 230 /** 231 * Generates code required to embed the player. 232 * 233 * The returned code contains a placeholder comment '<!--FALLBACK-->' 234 * (constant core_media_player::PLACEHOLDER) which indicates the location 235 * where fallback content should be placed in the event that this type of 236 * player is not supported by user browser. 237 * 238 * The $urls parameter includes one or more alternative media formats that 239 * are supported by this player. It does not include formats that aren't 240 * supported (see list_supported_urls). 241 * 242 * The $options array contains key-value pairs. See OPTION_xx constants 243 * for documentation of standard option(s). 244 * 245 * @param array $urls URLs of media files 246 * @param string $name Display name; '' to use default 247 * @param int $width Optional width; 0 to use default 248 * @param int $height Optional height; 0 to use default 249 * @param array $options Options array 250 * @return string HTML code for embed 251 */ 252 public abstract function embed($urls, $name, $width, $height, $options); 253 254 /** 255 * Gets the list of file extensions supported by this media player. 256 * 257 * Note: This is only required for the default implementation of 258 * list_supported_urls. If you override that function to determine 259 * supported URLs in some way other than by extension, then this function 260 * is not necessary. 261 * 262 * @return array Array of strings (extension not including dot e.g. 'mp3') 263 */ 264 public function get_supported_extensions() { 265 return array(); 266 } 267 268 /** 269 * Lists keywords that must be included in a url that can be embedded with 270 * this player. Any such keywords should be added to the array. 271 * 272 * For example if this player supports FLV and F4V files then it should add 273 * '.flv' and '.f4v' to the array. (The check is not case-sensitive.) 274 * 275 * Default handling calls the get_supported_extensions function and adds 276 * a dot to each of those values, so players only need to override this 277 * if they don't implement get_supported_extensions. 278 * 279 * This is used to improve performance when matching links in the media filter. 280 * 281 * @return array Array of keywords to add to the embeddable markers list 282 */ 283 public function get_embeddable_markers() { 284 $markers = array(); 285 foreach ($this->get_supported_extensions() as $extension) { 286 $markers[] = '.' . $extension; 287 } 288 return $markers; 289 } 290 291 /** 292 * Gets the ranking of this player. This is an integer used to decide which 293 * player to use (after applying other considerations such as which ones 294 * the user has disabled). 295 * 296 * Rank must be unique (no two players should have the same rank). 297 * 298 * Rank zero has a special meaning, indicating that this 'player' does not 299 * really embed the video. 300 * 301 * Rank is not a user-configurable value because it needs to be defined 302 * carefully in order to ensure that the embedding fallbacks actually work. 303 * It might be possible to have some user options which affect rank, but 304 * these would be best defined as e.g. checkboxes in settings that have 305 * a particular effect on the rank of a couple of plugins, rather than 306 * letting users generally alter rank. 307 * 308 * Note: Within medialib.php, players are listed in rank order (highest 309 * rank first). 310 * 311 * @return int Rank (higher is better) 312 */ 313 public abstract function get_rank(); 314 315 /** 316 * @return bool True if player is enabled 317 */ 318 public function is_enabled() { 319 global $CFG; 320 321 // With the class core_media_player_html5video it is enabled 322 // based on $CFG->core_media_enable_html5video. 323 $setting = str_replace('_player_', '_enable_', get_class($this)); 324 return !empty($CFG->{$setting}); 325 } 326 327 /** 328 * Given a list of URLs, returns a reduced array containing only those URLs 329 * which are supported by this player. (Empty if none.) 330 * @param array $urls Array of moodle_url 331 * @param array $options Options (same as will be passed to embed) 332 * @return array Array of supported moodle_url 333 */ 334 public function list_supported_urls(array $urls, array $options = array()) { 335 $extensions = $this->get_supported_extensions(); 336 $result = array(); 337 foreach ($urls as $url) { 338 if (in_array(core_media::get_extension($url), $extensions)) { 339 $result[] = $url; 340 } 341 } 342 return $result; 343 } 344 345 /** 346 * Obtains suitable name for media. Uses specified name if there is one, 347 * otherwise makes one up. 348 * @param string $name User-specified name ('' if none) 349 * @param array $urls Array of moodle_url used to make up name 350 * @return string Name 351 */ 352 protected function get_name($name, $urls) { 353 // If there is a specified name, use that. 354 if ($name) { 355 return $name; 356 } 357 358 // Get filename of first URL. 359 $url = reset($urls); 360 $name = core_media::get_filename($url); 361 362 // If there is more than one url, strip the extension as we could be 363 // referring to a different one or several at once. 364 if (count($urls) > 1) { 365 $name = preg_replace('~\.[^.]*$~', '', $name); 366 } 367 368 return $name; 369 } 370 371 /** 372 * Compares by rank order, highest first. Used for sort functions. 373 * @param core_media_player $a Player A 374 * @param core_media_player $b Player B 375 * @return int Negative if A should go before B, positive for vice versa 376 */ 377 public static function compare_by_rank(core_media_player $a, core_media_player $b) { 378 return $b->get_rank() - $a->get_rank(); 379 } 380 381 /** 382 * Utility function that sets width and height to defaults if not specified 383 * as a parameter to the function (will be specified either if, (a) the calling 384 * code passed it, or (b) the URL included it). 385 * @param int $width Width passed to function (updated with final value) 386 * @param int $height Height passed to function (updated with final value) 387 */ 388 protected static function pick_video_size(&$width, &$height) { 389 if (!$width) { 390 $width = CORE_MEDIA_VIDEO_WIDTH; 391 $height = CORE_MEDIA_VIDEO_HEIGHT; 392 } 393 } 394 } 395 396 397 /** 398 * Base class for players which handle external links (YouTube etc). 399 * 400 * As opposed to media files. 401 * 402 * @copyright 2011 The Open University 403 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 404 */ 405 abstract class core_media_player_external extends core_media_player { 406 /** 407 * Array of matches from regular expression - subclass can assume these 408 * will be valid when the embed function is called, to save it rerunning 409 * the regex. 410 * @var array 411 */ 412 protected $matches; 413 414 /** 415 * Part of a regular expression, including ending ~ symbol (note: these 416 * regexes use ~ instead of / because URLs and HTML code typically include 417 * / symbol and makes harder to read if you have to escape it). 418 * Matches the end part of a link after you have read the 'important' data 419 * including optional #d=400x300 at end of url, plus content of <a> tag, 420 * up to </a>. 421 * @var string 422 */ 423 const END_LINK_REGEX_PART = '[^#]*(#d=([\d]{1,4})x([\d]{1,4}))?~si'; 424 425 public function embed($urls, $name, $width, $height, $options) { 426 return $this->embed_external(reset($urls), $name, $width, $height, $options); 427 } 428 429 /** 430 * Obtains HTML code to embed the link. 431 * @param moodle_url $url Single URL to embed 432 * @param string $name Display name; '' to use default 433 * @param int $width Optional width; 0 to use default 434 * @param int $height Optional height; 0 to use default 435 * @param array $options Options array 436 * @return string HTML code for embed 437 */ 438 protected abstract function embed_external(moodle_url $url, $name, $width, $height, $options); 439 440 public function list_supported_urls(array $urls, array $options = array()) { 441 // These only work with a SINGLE url (there is no fallback). 442 if (count($urls) != 1) { 443 return array(); 444 } 445 $url = reset($urls); 446 447 // Check against regex. 448 if (preg_match($this->get_regex(), $url->out(false), $this->matches)) { 449 return array($url); 450 } 451 452 return array(); 453 } 454 455 /** 456 * Returns regular expression used to match URLs that this player handles 457 * @return string PHP regular expression e.g. '~^https?://example.org/~' 458 */ 459 protected function get_regex() { 460 return '~^unsupported~'; 461 } 462 463 /** 464 * Annoyingly, preg_match $matches result does not always have the same 465 * number of parameters - it leaves out optional ones at the end. WHAT. 466 * Anyway, this function can be used to fix it. 467 * @param array $matches Array that should be adjusted 468 * @param int $count Number of capturing groups (=6 to make $matches[6] work) 469 */ 470 protected static function fix_match_count(&$matches, $count) { 471 for ($i = count($matches); $i <= $count; $i++) { 472 $matches[$i] = false; 473 } 474 } 475 } 476 477 478 /** 479 * Player that embeds Vimeo links. 480 * 481 * @copyright 2011 The Open University 482 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 483 */ 484 class core_media_player_vimeo extends core_media_player_external { 485 protected function embed_external(moodle_url $url, $name, $width, $height, $options) { 486 $videoid = $this->matches[1]; 487 $info = s($name); 488 489 // Note: resizing via url is not supported, user can click the fullscreen 490 // button instead. iframe embedding is not xhtml strict but it is the only 491 // option that seems to work on most devices. 492 self::pick_video_size($width, $height); 493 494 $output = <<<OET 495 <span class="mediaplugin mediaplugin_vimeo"> 496 <iframe title="$info" src="https://player.vimeo.com/video/$videoid" 497 width="$width" height="$height" frameborder="0" 498 webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> 499 </span> 500 OET; 501 502 return $output; 503 } 504 505 protected function get_regex() { 506 // Initial part of link. 507 $start = '~^https?://vimeo\.com/'; 508 // Middle bit: either watch?v= or v/. 509 $middle = '([0-9]+)'; 510 return $start . $middle . core_media_player_external::END_LINK_REGEX_PART; 511 } 512 513 public function get_rank() { 514 return 1010; 515 } 516 517 public function get_embeddable_markers() { 518 return array('vimeo.com/'); 519 } 520 } 521 522 /** 523 * Player that creates YouTube embedding. 524 * 525 * @copyright 2011 The Open University 526 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 527 */ 528 class core_media_player_youtube extends core_media_player_external { 529 protected function embed_external(moodle_url $url, $name, $width, $height, $options) { 530 $videoid = end($this->matches); 531 532 $info = trim($name); 533 if (empty($info) or strpos($info, 'http') === 0) { 534 $info = get_string('siteyoutube', 'core_media'); 535 } 536 $info = s($info); 537 538 self::pick_video_size($width, $height); 539 540 $params = ''; 541 $start = self::get_start_time($url); 542 if ($start > 0) { 543 $params .= "start=$start&"; 544 } 545 546 $listid = $url->param('list'); 547 // Check for non-empty but valid playlist ID. 548 if (!empty($listid) && !preg_match('/[^a-zA-Z0-9\-_]/', $listid)) { 549 // This video is part of a playlist, and we want to embed it as such. 550 $params .= "list=$listid&"; 551 } 552 553 return <<<OET 554 <span class="mediaplugin mediaplugin_youtube"> 555 <iframe title="$info" width="$width" height="$height" 556 src="https://www.youtube.com/embed/$videoid?{$params}rel=0&wmode=transparent" frameborder="0" allowfullscreen="1"></iframe> 557 </span> 558 OET; 559 560 } 561 562 /** 563 * Check for start time parameter. Note that it's in hours/mins/secs in the URL, 564 * but the embedded player takes only a number of seconds as the "start" parameter. 565 * @param moodle_url $url URL of video to be embedded. 566 * @return int Number of seconds video should start at. 567 */ 568 protected static function get_start_time($url) { 569 $matches = array(); 570 $seconds = 0; 571 572 $rawtime = $url->param('t'); 573 if (empty($rawtime)) { 574 $rawtime = $url->param('start'); 575 } 576 577 if (is_numeric($rawtime)) { 578 // Start time already specified as a number of seconds; ensure it's an integer. 579 $seconds = $rawtime; 580 } else if (preg_match('/(\d+?h)?(\d+?m)?(\d+?s)?/i', $rawtime, $matches)) { 581 // Convert into a raw number of seconds, as that's all embedded players accept. 582 for ($i = 1; $i < count($matches); $i++) { 583 if (empty($matches[$i])) { 584 continue; 585 } 586 $part = str_split($matches[$i], strlen($matches[$i]) - 1); 587 switch ($part[1]) { 588 case 'h': 589 $seconds += 3600 * $part[0]; 590 break; 591 case 'm': 592 $seconds += 60 * $part[0]; 593 break; 594 default: 595 $seconds += $part[0]; 596 } 597 } 598 } 599 600 return intval($seconds); 601 } 602 603 protected function get_regex() { 604 // Regex for standard youtube link 605 $link = '(youtube(-nocookie)?\.com/(?:watch\?v=|v/))'; 606 // Regex for shortened youtube link 607 $shortlink = '((youtu|y2u)\.be/)'; 608 609 // Initial part of link. 610 $start = '~^https?://(www\.)?(' . $link . '|' . $shortlink . ')'; 611 // Middle bit: Video key value 612 $middle = '([a-z0-9\-_]+)'; 613 return $start . $middle . core_media_player_external::END_LINK_REGEX_PART; 614 } 615 616 public function get_rank() { 617 // I decided to make the link-embedding ones (that don't handle file 618 // formats) have ranking in the 1000 range. 619 return 1001; 620 } 621 622 public function get_embeddable_markers() { 623 return array('youtube.com', 'youtube-nocookie.com', 'youtu.be', 'y2u.be'); 624 } 625 } 626 627 628 /** 629 * Player that creates YouTube playlist embedding. 630 * 631 * @copyright 2011 The Open University 632 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 633 */ 634 class core_media_player_youtube_playlist extends core_media_player_external { 635 public function is_enabled() { 636 global $CFG; 637 // Use the youtube on/off flag. 638 return $CFG->core_media_enable_youtube; 639 } 640 641 protected function embed_external(moodle_url $url, $name, $width, $height, $options) { 642 $site = $this->matches[1]; 643 $playlist = $this->matches[3]; 644 645 $info = trim($name); 646 if (empty($info) or strpos($info, 'http') === 0) { 647 $info = get_string('siteyoutube', 'core_media'); 648 } 649 $info = s($info); 650 651 self::pick_video_size($width, $height); 652 653 return <<<OET 654 <span class="mediaplugin mediaplugin_youtube"> 655 <iframe width="$width" height="$height" src="https://$site/embed/videoseries?list=$playlist" frameborder="0" allowfullscreen="1"></iframe> 656 </span> 657 OET; 658 } 659 660 protected function get_regex() { 661 // Initial part of link. 662 $start = '~^https?://(www\.youtube(-nocookie)?\.com)/'; 663 // Middle bit: either view_play_list?p= or p/ (doesn't work on youtube) or playlist?list=. 664 $middle = '(?:view_play_list\?p=|p/|playlist\?list=)([a-z0-9\-_]+)'; 665 return $start . $middle . core_media_player_external::END_LINK_REGEX_PART; 666 } 667 668 public function get_rank() { 669 // I decided to make the link-embedding ones (that don't handle file 670 // formats) have ranking in the 1000 range. 671 return 1000; 672 } 673 674 public function get_embeddable_markers() { 675 return array('youtube'); 676 } 677 } 678 679 680 /** 681 * MP3 player inserted using JavaScript. 682 * 683 * @copyright 2011 The Open University 684 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 685 */ 686 class core_media_player_mp3 extends core_media_player { 687 public function embed($urls, $name, $width, $height, $options) { 688 // Use first url (there can actually be only one unless some idiot 689 // enters two mp3 files as alternatives). 690 $url = reset($urls); 691 692 // Unique id even across different http requests made at the same time 693 // (for AJAX, iframes). 694 $id = 'core_media_mp3_' . md5(time() . '_' . rand()); 695 696 // When Flash or JavaScript are not available only the fallback is displayed, 697 // using span not div because players are inline elements. 698 $spanparams = array('id' => $id, 'class' => 'mediaplugin mediaplugin_mp3'); 699 if ($width) { 700 $spanparams['style'] = 'width: ' . $width . 'px'; 701 } 702 $output = html_writer::tag('span', core_media_player::PLACEHOLDER, $spanparams); 703 // We can not use standard JS init because this may be cached 704 // note: use 'small' size unless embedding in block mode. 705 $output .= html_writer::script(js_writer::function_call( 706 'M.util.add_audio_player', array($id, $url->out(false), 707 empty($options[core_media::OPTION_BLOCK])))); 708 709 return $output; 710 } 711 712 public function get_supported_extensions() { 713 return array('mp3'); 714 } 715 716 public function get_rank() { 717 return 80; 718 } 719 } 720 721 722 /** 723 * Flash video player inserted using JavaScript. 724 * 725 * @copyright 2011 The Open University 726 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 727 */ 728 class core_media_player_flv extends core_media_player { 729 public function embed($urls, $name, $width, $height, $options) { 730 // Use first url (there can actually be only one unless some idiot 731 // enters two mp3 files as alternatives). 732 $url = reset($urls); 733 734 // Unique id even across different http requests made at the same time 735 // (for AJAX, iframes). 736 $id = 'core_media_flv_' . md5(time() . '_' . rand()); 737 738 // Compute width and height. 739 $autosize = false; 740 if (!$width && !$height) { 741 $width = CORE_MEDIA_VIDEO_WIDTH; 742 $height = CORE_MEDIA_VIDEO_HEIGHT; 743 $autosize = true; 744 } 745 746 // Fallback span (will normally contain link). 747 $output = html_writer::tag('span', core_media_player::PLACEHOLDER, 748 array('id'=>$id, 'class'=>'mediaplugin mediaplugin_flv')); 749 // We can not use standard JS init because this may be cached. 750 $output .= html_writer::script(js_writer::function_call( 751 'M.util.add_video_player', array($id, addslashes_js($url->out(false)), 752 $width, $height, $autosize))); 753 return $output; 754 } 755 756 public function get_supported_extensions() { 757 return array('flv', 'f4v'); 758 } 759 760 public function get_rank() { 761 return 70; 762 } 763 } 764 765 766 /** 767 * Embeds Windows Media Player using object tag. 768 * 769 * @copyright 2011 The Open University 770 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 771 */ 772 class core_media_player_wmp extends core_media_player { 773 public function embed($urls, $name, $width, $height, $options) { 774 // Get URL (we just use first, probably there is only one). 775 $firsturl = reset($urls); 776 $url = $firsturl->out(false); 777 778 // Work out width. 779 if (!$width || !$height) { 780 // Object tag has default size. 781 $mpsize = ''; 782 $size = 'width="' . CORE_MEDIA_VIDEO_WIDTH . 783 '" height="' . (CORE_MEDIA_VIDEO_HEIGHT+64) . '"'; 784 $autosize = 'true'; 785 } else { 786 $size = 'width="' . $width . '" height="' . ($height + 15) . '"'; 787 $mpsize = 'width="' . $width . '" height="' . ($height + 64) . '"'; 788 $autosize = 'false'; 789 } 790 791 // MIME type for object tag. 792 $mimetype = core_media::get_mimetype($firsturl); 793 794 $fallback = core_media_player::PLACEHOLDER; 795 796 // Embed code. 797 return <<<OET 798 <span class="mediaplugin mediaplugin_wmp"> 799 <object classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6" $mpsize 800 standby="Loading Microsoft(R) Windows(R) Media Player components..." 801 type="application/x-oleobject"> 802 <param name="Filename" value="$url" /> 803 <param name="src" value="$url" /> 804 <param name="url" value="$url" /> 805 <param name="ShowControls" value="true" /> 806 <param name="AutoRewind" value="true" /> 807 <param name="AutoStart" value="false" /> 808 <param name="Autosize" value="$autosize" /> 809 <param name="EnableContextMenu" value="true" /> 810 <param name="TransparentAtStart" value="false" /> 811 <param name="AnimationAtStart" value="false" /> 812 <param name="ShowGotoBar" value="false" /> 813 <param name="EnableFullScreenControls" value="true" /> 814 <param name="uimode" value="full" /> 815 <!--[if !IE]><!--> 816 <object data="$url" type="$mimetype" $size> 817 <param name="src" value="$url" /> 818 <param name="controller" value="true" /> 819 <param name="autoplay" value="false" /> 820 <param name="autostart" value="false" /> 821 <param name="resize" value="scale" /> 822 <!--<![endif]--> 823 $fallback 824 <!--[if !IE]><!--> 825 </object> 826 <!--<![endif]--> 827 </object> 828 </span> 829 OET; 830 } 831 832 public function get_supported_extensions() { 833 return array('wmv', 'avi'); 834 } 835 836 public function get_rank() { 837 return 60; 838 } 839 } 840 841 842 /** 843 * Media player using object tag and QuickTime player. 844 * 845 * @copyright 2011 The Open University 846 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 847 */ 848 class core_media_player_qt extends core_media_player { 849 public function embed($urls, $name, $width, $height, $options) { 850 // Show first URL. 851 $firsturl = reset($urls); 852 $url = $firsturl->out(true); 853 854 // Work out size. 855 if (!$width || !$height) { 856 $size = 'width="' . CORE_MEDIA_VIDEO_WIDTH . 857 '" height="' . (CORE_MEDIA_VIDEO_HEIGHT + 15) . '"'; 858 } else { 859 $size = 'width="' . $width . '" height="' . ($height + 15) . '"'; 860 } 861 862 // MIME type for object tag. 863 $mimetype = core_media::get_mimetype($firsturl); 864 865 $fallback = core_media_player::PLACEHOLDER; 866 867 // Embed code. 868 return <<<OET 869 <span class="mediaplugin mediaplugin_qt"> 870 <object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" 871 codebase="http://www.apple.com/qtactivex/qtplugin.cab" $size> 872 <param name="pluginspage" value="http://www.apple.com/quicktime/download/" /> 873 <param name="src" value="$url" /> 874 <param name="controller" value="true" /> 875 <param name="loop" value="false" /> 876 <param name="autoplay" value="false" /> 877 <param name="autostart" value="false" /> 878 <param name="scale" value="aspect" /> 879 <!--[if !IE]><!--> 880 <object data="$url" type="$mimetype" $size> 881 <param name="src" value="$url" /> 882 <param name="pluginurl" value="http://www.apple.com/quicktime/download/" /> 883 <param name="controller" value="true" /> 884 <param name="loop" value="false" /> 885 <param name="autoplay" value="false" /> 886 <param name="autostart" value="false" /> 887 <param name="scale" value="aspect" /> 888 <!--<![endif]--> 889 $fallback 890 <!--[if !IE]><!--> 891 </object> 892 <!--<![endif]--> 893 </object> 894 </span> 895 OET; 896 } 897 898 public function get_supported_extensions() { 899 return array('mpg', 'mpeg', 'mov', 'mp4', 'm4v', 'm4a'); 900 } 901 902 public function get_rank() { 903 return 10; 904 } 905 } 906 907 908 /** 909 * Media player using object tag and RealPlayer. 910 * 911 * Hopefully nobody is using this obsolete format any more! 912 * 913 * @copyright 2011 The Open University 914 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 915 */ 916 class core_media_player_rm extends core_media_player { 917 public function embed($urls, $name, $width, $height, $options) { 918 // Show first URL. 919 $firsturl = reset($urls); 920 $url = $firsturl->out(true); 921 922 // Get name to use as title. 923 $info = s($this->get_name($name, $urls)); 924 925 // The previous version of this code has the following comment, which 926 // I don't understand, but trust it is correct: 927 // Note: the size is hardcoded intentionally because this does not work anyway! 928 $width = CORE_MEDIA_VIDEO_WIDTH; 929 $height = CORE_MEDIA_VIDEO_HEIGHT; 930 931 $fallback = core_media_player::PLACEHOLDER; 932 return <<<OET 933 <span class="mediaplugin mediaplugin_real"> 934 <object title="$info" classid="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" 935 data="$url" width="$width" height="$height""> 936 <param name="src" value="$url" /> 937 <param name="controls" value="All" /> 938 <!--[if !IE]><!--> 939 <object title="$info" type="audio/x-pn-realaudio-plugin" 940 data="$url" width="$width" height="$height"> 941 <param name="src" value="$url" /> 942 <param name="controls" value="All" /> 943 <!--<![endif]--> 944 $fallback 945 <!--[if !IE]><!--> 946 </object> 947 <!--<![endif]--> 948 </object> 949 </span> 950 OET; 951 } 952 953 public function get_supported_extensions() { 954 return array('ra', 'ram', 'rm', 'rv'); 955 } 956 957 public function get_rank() { 958 return 40; 959 } 960 } 961 962 963 /** 964 * Media player for Flash SWF files. 965 * 966 * This player contains additional security restriction: it will only be used 967 * if you add option core_media_player_swf::ALLOW = true. 968 * 969 * Code should only set this option if it has verified that the data was 970 * embedded by a trusted user (e.g. in trust text). 971 * 972 * @copyright 2011 The Open University 973 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 974 */ 975 class core_media_player_swf extends core_media_player { 976 public function embed($urls, $name, $width, $height, $options) { 977 self::pick_video_size($width, $height); 978 979 $firsturl = reset($urls); 980 $url = $firsturl->out(true); 981 982 $fallback = core_media_player::PLACEHOLDER; 983 $output = <<<OET 984 <span class="mediaplugin mediaplugin_swf"> 985 <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="$width" height="$height"> 986 <param name="movie" value="$url" /> 987 <param name="autoplay" value="true" /> 988 <param name="loop" value="false" /> 989 <param name="controller" value="true" /> 990 <param name="scale" value="aspect" /> 991 <param name="base" value="." /> 992 <param name="allowscriptaccess" value="never" /> 993 <param name="allowfullscreen" value="true" /> 994 <!--[if !IE]><!--> 995 <object type="application/x-shockwave-flash" data="$url" width="$width" height="$height"> 996 <param name="controller" value="true" /> 997 <param name="autoplay" value="true" /> 998 <param name="loop" value="false" /> 999 <param name="scale" value="aspect" /> 1000 <param name="base" value="." /> 1001 <param name="allowscriptaccess" value="never" /> 1002 <param name="allowfullscreen" value="true" /> 1003 <!--<![endif]--> 1004 $fallback 1005 <!--[if !IE]><!--> 1006 </object> 1007 <!--<![endif]--> 1008 </object> 1009 </span> 1010 OET; 1011 1012 return $output; 1013 } 1014 1015 public function get_supported_extensions() { 1016 return array('swf'); 1017 } 1018 1019 public function list_supported_urls(array $urls, array $options = array()) { 1020 // Not supported unless the creator is trusted. 1021 if (empty($options[core_media::OPTION_TRUSTED])) { 1022 return array(); 1023 } 1024 return parent::list_supported_urls($urls, $options); 1025 } 1026 1027 public function get_rank() { 1028 return 30; 1029 } 1030 } 1031 1032 1033 /** 1034 * Player that creates HTML5 <video> tag. 1035 * 1036 * @copyright 2011 The Open University 1037 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1038 */ 1039 class core_media_player_html5video extends core_media_player { 1040 public function embed($urls, $name, $width, $height, $options) { 1041 // Special handling to make videos play on Android devices pre 2.3. 1042 // Note: I tested and 2.3.3 (in emulator) works without, is 533.1 webkit. 1043 $oldandroid = core_useragent::is_webkit_android() && 1044 !core_useragent::check_webkit_android_version('533.1'); 1045 1046 // Build array of source tags. 1047 $sources = array(); 1048 foreach ($urls as $url) { 1049 $mimetype = core_media::get_mimetype($url); 1050 $source = html_writer::tag('source', '', array('src' => $url, 'type' => $mimetype)); 1051 if ($mimetype === 'video/mp4') { 1052 if ($oldandroid) { 1053 // Old Android fails if you specify the type param. 1054 $source = html_writer::tag('source', '', array('src' => $url)); 1055 } 1056 1057 // Better add m4v as first source, it might be a bit more 1058 // compatible with problematic browsers. 1059 array_unshift($sources, $source); 1060 } else { 1061 $sources[] = $source; 1062 } 1063 } 1064 1065 $sources = implode("\n", $sources); 1066 $title = s($this->get_name($name, $urls)); 1067 1068 if (!$width) { 1069 // No width specified, use system default. 1070 $width = CORE_MEDIA_VIDEO_WIDTH; 1071 } 1072 1073 if (!$height) { 1074 // Let browser choose height automatically. 1075 $size = "width=\"$width\""; 1076 } else { 1077 $size = "width=\"$width\" height=\"$height\""; 1078 } 1079 1080 $sillyscript = ''; 1081 $idtag = ''; 1082 if ($oldandroid) { 1083 // Old Android does not support 'controls' option. 1084 $id = 'core_media_html5v_' . md5(time() . '_' . rand()); 1085 $idtag = 'id="' . $id . '"'; 1086 $sillyscript = <<<OET 1087 <script type="text/javascript"> 1088 document.getElementById('$id').addEventListener('click', function() { 1089 this.play(); 1090 }, false); 1091 </script> 1092 OET; 1093 } 1094 1095 $fallback = core_media_player::PLACEHOLDER; 1096 return <<<OET 1097 <span class="mediaplugin mediaplugin_html5video"> 1098 <video $idtag controls="true" $size preload="metadata" title="$title"> 1099 $sources 1100 $fallback 1101 </video> 1102 $sillyscript 1103 </span> 1104 OET; 1105 } 1106 1107 public function get_supported_extensions() { 1108 return array('m4v', 'webm', 'ogv', 'mp4'); 1109 } 1110 1111 public function list_supported_urls(array $urls, array $options = array()) { 1112 $extensions = $this->get_supported_extensions(); 1113 $result = array(); 1114 foreach ($urls as $url) { 1115 $ext = core_media::get_extension($url); 1116 if (in_array($ext, $extensions)) { 1117 // Unfortunately html5 video does not handle fallback properly. 1118 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=10975 1119 // That means we need to do browser detect and not use html5 on 1120 // browsers which do not support the given type, otherwise users 1121 // will not even see the fallback link. 1122 // Based on http://en.wikipedia.org/wiki/HTML5_video#Table - this 1123 // is a simplified version, does not take into account old browser 1124 // versions or manual plugins. 1125 if ($ext === 'ogv' || $ext === 'webm') { 1126 // Formats .ogv and .webm are not supported in IE, Edge or Safari. 1127 if (core_useragent::is_ie() || core_useragent::is_edge() || core_useragent::is_safari()) { 1128 continue; 1129 } 1130 } else { 1131 // Formats .m4v and .mp4 are not supported in Opera, or in Firefox before 27. 1132 // https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats 1133 // has the details. 1134 if (core_useragent::is_opera() || (core_useragent::is_firefox() && 1135 !core_useragent::check_firefox_version(27))) { 1136 continue; 1137 } 1138 } 1139 1140 $result[] = $url; 1141 } 1142 } 1143 return $result; 1144 } 1145 1146 public function get_rank() { 1147 return 50; 1148 } 1149 } 1150 1151 1152 /** 1153 * Player that creates HTML5 <audio> tag. 1154 * 1155 * @copyright 2011 The Open University 1156 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1157 */ 1158 class core_media_player_html5audio extends core_media_player { 1159 public function embed($urls, $name, $width, $height, $options) { 1160 1161 // Build array of source tags. 1162 $sources = array(); 1163 foreach ($urls as $url) { 1164 $mimetype = core_media::get_mimetype($url); 1165 $sources[] = html_writer::tag('source', '', array('src' => $url, 'type' => $mimetype)); 1166 } 1167 1168 $sources = implode("\n", $sources); 1169 $title = s($this->get_name($name, $urls)); 1170 1171 // Default to not specify size (so it can be changed in css). 1172 $size = ''; 1173 if ($width) { 1174 $size = 'width="' . $width . '"'; 1175 } 1176 1177 $fallback = core_media_player::PLACEHOLDER; 1178 1179 return <<<OET 1180 <audio controls="true" $size class="mediaplugin mediaplugin_html5audio" preload="none" title="$title"> 1181 $sources 1182 $fallback 1183 </audio> 1184 OET; 1185 } 1186 1187 public function get_supported_extensions() { 1188 return array('ogg', 'oga', 'aac', 'm4a', 'mp3'); 1189 } 1190 1191 public function list_supported_urls(array $urls, array $options = array()) { 1192 $extensions = $this->get_supported_extensions(); 1193 $result = array(); 1194 foreach ($urls as $url) { 1195 $ext = core_media::get_extension($url); 1196 if (in_array($ext, $extensions)) { 1197 if ($ext === 'ogg' || $ext === 'oga') { 1198 // Formats .ogg and .oga are not supported in IE, Edge, or Safari. 1199 if (core_useragent::is_ie() || core_useragent::is_edge() || core_useragent::is_safari()) { 1200 continue; 1201 } 1202 } else { 1203 // Formats .aac, .mp3, and .m4a are not supported in Opera. 1204 if (core_useragent::is_opera()) { 1205 continue; 1206 } 1207 // Formats .mp3 and .m4a were not reliably supported in Firefox before 27. 1208 // https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats 1209 // has the details. .aac is still not supported. 1210 if (core_useragent::is_firefox() && ($ext === 'aac' || 1211 !core_useragent::check_firefox_version(27))) { 1212 continue; 1213 } 1214 } 1215 // Old Android versions (pre 2.3.3) 'support' audio tag but no codecs. 1216 if (core_useragent::is_webkit_android() && 1217 !core_useragent::is_webkit_android('533.1')) { 1218 continue; 1219 } 1220 1221 $result[] = $url; 1222 } 1223 } 1224 return $result; 1225 } 1226 1227 public function get_rank() { 1228 return 20; 1229 } 1230 } 1231 1232 1233 /** 1234 * Special media player class that just puts a link. 1235 * 1236 * Always enabled, used as the last fallback. 1237 * 1238 * @copyright 2011 The Open University 1239 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1240 */ 1241 class core_media_player_link extends core_media_player { 1242 public function embed($urls, $name, $width, $height, $options) { 1243 // If link is turned off, return empty. 1244 if (!empty($options[core_media::OPTION_NO_LINK])) { 1245 return ''; 1246 } 1247 1248 // Build up link content. 1249 $output = ''; 1250 foreach ($urls as $url) { 1251 $title = core_media::get_filename($url); 1252 $printlink = html_writer::link($url, $title, array('class' => 'mediafallbacklink')); 1253 if ($output) { 1254 // Where there are multiple available formats, there are fallback links 1255 // for all formats, separated by /. 1256 $output .= ' / '; 1257 } 1258 $output .= $printlink; 1259 } 1260 return $output; 1261 } 1262 1263 public function list_supported_urls(array $urls, array $options = array()) { 1264 // Supports all URLs. 1265 return $urls; 1266 } 1267 1268 public function is_enabled() { 1269 // Cannot be disabled. 1270 return true; 1271 } 1272 1273 public function get_rank() { 1274 return 0; 1275 } 1276 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |