Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]

   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  namespace core;
  18  
  19  use core_media_manager;
  20  use media_test_plugin;
  21  
  22  defined('MOODLE_INTERNAL') || die();
  23  require_once (__DIR__ . '/fixtures/testable_core_media_player.php');
  24  
  25  /**
  26   * Test classes for handling embedded media (audio/video).
  27   *
  28   * @package   core
  29   * @category  test
  30   * @copyright 2012 The Open University
  31   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  32   */
  33  class medialib_test extends \advanced_testcase {
  34  
  35      /**
  36       * Pre-test setup. Preserves $CFG.
  37       */
  38      public function setUp(): void {
  39          parent::setUp();
  40  
  41          // Reset $CFG and $SERVER.
  42          $this->resetAfterTest();
  43  
  44          // "Install" a fake plugin for testing.
  45          set_config('version', '2016101400', 'media_test');
  46  
  47          // Consistent initial setup: all players disabled.
  48          \core\plugininfo\media::set_enabled_plugins('');
  49  
  50          $_SERVER = array('HTTP_USER_AGENT' => '');
  51          $this->pretend_to_be_safari();
  52      }
  53  
  54      /**
  55       * Sets user agent to Safari.
  56       */
  57      private function pretend_to_be_safari() {
  58          // Pretend to be using Safari browser (must support mp4 for tests to work).
  59          \core_useragent::instance(true, 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) ' .
  60                  'AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1');
  61      }
  62  
  63      /**
  64       * Sets user agent to Firefox.
  65       */
  66      private function pretend_to_be_firefox() {
  67          // Pretend to be using Firefox browser (must support ogg for tests to work).
  68          \core_useragent::instance(true, 'Mozilla/5.0 (X11; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0 ');
  69      }
  70  
  71      /**
  72       * Test for core_media::get_filename.
  73       */
  74      public function test_get_filename() {
  75          $manager = core_media_manager::instance();
  76  
  77          $this->assertSame('frog.mp4', $manager->get_filename(new \moodle_url(
  78                  '/pluginfile.php/312/mod_page/content/7/frog.mp4')));
  79          // This should work even though slasharguments is true, because we want
  80          // it to support 'legacy' links if somebody toggles the option later.
  81          $this->assertSame('frog.mp4', $manager->get_filename(new \moodle_url(
  82                  '/pluginfile.php?file=/312/mod_page/content/7/frog.mp4')));
  83      }
  84  
  85      /**
  86       * Test for core_media::get_extension.
  87       */
  88      public function test_get_extension() {
  89          $manager = core_media_manager::instance();
  90  
  91          $this->assertSame('mp4', $manager->get_extension(new \moodle_url(
  92                  '/pluginfile.php/312/mod_page/content/7/frog.mp4')));
  93          $this->assertSame('', $manager->get_extension(new \moodle_url(
  94                  '/pluginfile.php/312/mod_page/content/7/frog')));
  95          $this->assertSame('mp4', $manager->get_extension(new \moodle_url(
  96                  '/pluginfile.php?file=/312/mod_page/content/7/frog.mp4')));
  97          $this->assertSame('', $manager->get_extension(new \moodle_url(
  98                  '/pluginfile.php?file=/312/mod_page/content/7/frog')));
  99      }
 100  
 101      /**
 102       * Test for the core_media_player list_supported_urls.
 103       */
 104      public function test_list_supported_urls() {
 105          $test = new media_test_plugin(1, 13, ['tst', 'test']);
 106  
 107          // Some example URLs.
 108          $supported1 = new \moodle_url('http://example.org/1.test');
 109          $supported2 = new \moodle_url('http://example.org/2.TST');
 110          $unsupported = new \moodle_url('http://example.org/2.jpg');
 111  
 112          // No URLs => none.
 113          $result = $test->list_supported_urls(array());
 114          $this->assertEquals(array(), $result);
 115  
 116          // One supported URL => same.
 117          $result = $test->list_supported_urls(array($supported1));
 118          $this->assertEquals(array($supported1), $result);
 119  
 120          // Two supported URLS => same.
 121          $result = $test->list_supported_urls(array($supported1, $supported2));
 122          $this->assertEquals(array($supported1, $supported2), $result);
 123  
 124          // One unsupported => none.
 125          $result = $test->list_supported_urls(array($unsupported));
 126          $this->assertEquals(array(), $result);
 127  
 128          // Two supported and one unsupported => same.
 129          $result = $test->list_supported_urls(array($supported2, $unsupported, $supported1));
 130          $this->assertEquals(array($supported2, $supported1), $result);
 131      }
 132  
 133      /**
 134       * Test for get_players
 135       */
 136      public function test_get_players() {
 137          // All players are initially disabled (except link, which you can't).
 138          $manager = core_media_manager::instance();
 139          $this->assertEmpty($this->get_players_test($manager));
 140  
 141          // A couple enabled, check the order.
 142          \core\plugininfo\media::set_enabled_plugins('youtube,html5audio');
 143          $manager = core_media_manager::instance();
 144          $this->assertSame('youtube, html5audio', $this->get_players_test($manager));
 145  
 146          // Test SWF and HTML5 media order.
 147          \core\plugininfo\media::set_enabled_plugins('html5video,html5audio,swf');
 148          $manager = core_media_manager::instance();
 149          $this->assertSame('html5video, html5audio, swf', $this->get_players_test($manager));
 150  
 151          // Make sure that our test plugin is considered installed.
 152          \core\plugininfo\media::set_enabled_plugins('test,html5video');
 153          $manager = core_media_manager::instance();
 154          $this->assertSame('test, html5video', $this->get_players_test($manager));
 155  
 156          // Make sure that non-existing plugin is NOT considered installed.
 157          \core\plugininfo\media::set_enabled_plugins('nonexistingplugin,html5video');
 158          $manager = core_media_manager::instance();
 159          $this->assertSame('html5video', $this->get_players_test($manager));
 160      }
 161  
 162      /**
 163       * Test for can_embed_url
 164       */
 165      public function test_can_embed_url() {
 166          // All players are initially disabled, so mp4 cannot be rendered.
 167          $url = new \moodle_url('http://example.org/test.mp4');
 168          $manager = core_media_manager::instance();
 169          $this->assertFalse($manager->can_embed_url($url));
 170  
 171          // Enable VideoJS player.
 172          \core\plugininfo\media::set_enabled_plugins('videojs');
 173          $manager = core_media_manager::instance();
 174          $this->assertTrue($manager->can_embed_url($url));
 175  
 176          // VideoJS + html5.
 177          \core\plugininfo\media::set_enabled_plugins('videojs,html5video');
 178          $manager = core_media_manager::instance();
 179          $this->assertTrue($manager->can_embed_url($url));
 180  
 181          // Only html5.
 182          \core\plugininfo\media::set_enabled_plugins('html5video');
 183          $manager = core_media_manager::instance();
 184          $this->assertTrue($manager->can_embed_url($url));
 185  
 186          // Only SWF.
 187          \core\plugininfo\media::set_enabled_plugins('swf');
 188          $manager = core_media_manager::instance();
 189          $this->assertFalse($manager->can_embed_url($url));
 190      }
 191  
 192      /**
 193       * Test for embed_url.
 194       * Checks multiple format/fallback support.
 195       */
 196      public function test_embed_url_fallbacks() {
 197  
 198          // Key strings in the embed code that identify with the media formats being tested.
 199          $swf = '</object>';
 200          $html5video = '</video>';
 201          $html5audio = '</audio>';
 202          $link = 'mediafallbacklink';
 203          $test = 'mediaplugin_test';
 204  
 205          $url = new \moodle_url('http://example.org/test.mp4');
 206  
 207          // All plugins disabled, NOLINK option.
 208          \core\plugininfo\media::set_enabled_plugins('');
 209          $manager = core_media_manager::instance();
 210          $t = $manager->embed_url($url, 0, 0, '',
 211                  array(core_media_manager::OPTION_NO_LINK => true));
 212          // Completely empty.
 213          $this->assertSame('', $t);
 214  
 215          // All plugins disabled but not NOLINK.
 216          \core\plugininfo\media::set_enabled_plugins('');
 217          $manager = core_media_manager::instance();
 218          $t = $manager->embed_url($url);
 219          $this->assertStringContainsString($link, $t);
 220  
 221          // Enable media players that can play the same media formats. (ie. test & html5audio for mp3 files, etc.)
 222          \core\plugininfo\media::set_enabled_plugins('test,html5video,html5audio,swf');
 223          $manager = core_media_manager::instance();
 224  
 225          // Test media formats that can be played by 2 or more players.
 226          $mediaformats = array('mp3', 'mp4');
 227  
 228          foreach ($mediaformats as $format) {
 229              $url = new \moodle_url('http://example.org/test.' . $format);
 230              $textwithlink = $manager->embed_url($url);
 231              $textwithoutlink = $manager->embed_url($url, 0, 0, '', array(core_media_manager::OPTION_NO_LINK => true));
 232  
 233              switch ($format) {
 234                  case 'mp3':
 235                      $this->assertStringContainsString($test, $textwithlink);
 236                      $this->assertStringNotContainsString($html5video, $textwithlink);
 237                      $this->assertStringContainsString($html5audio, $textwithlink);
 238                      $this->assertStringNotContainsString($swf, $textwithlink);
 239                      $this->assertStringContainsString($link, $textwithlink);
 240  
 241                      $this->assertStringContainsString($test, $textwithoutlink);
 242                      $this->assertStringNotContainsString($html5video, $textwithoutlink);
 243                      $this->assertStringContainsString($html5audio, $textwithoutlink);
 244                      $this->assertStringNotContainsString($swf, $textwithoutlink);
 245                      $this->assertStringNotContainsString($link, $textwithoutlink);
 246                      break;
 247  
 248                  case 'mp4':
 249                      $this->assertStringContainsString($test, $textwithlink);
 250                      $this->assertStringContainsString($html5video, $textwithlink);
 251                      $this->assertStringNotContainsString($html5audio, $textwithlink);
 252                      $this->assertStringNotContainsString($swf, $textwithlink);
 253                      $this->assertStringContainsString($link, $textwithlink);
 254  
 255                      $this->assertStringContainsString($test, $textwithoutlink);
 256                      $this->assertStringContainsString($html5video, $textwithoutlink);
 257                      $this->assertStringNotContainsString($html5audio, $textwithoutlink);
 258                      $this->assertStringNotContainsString($swf, $textwithoutlink);
 259                      $this->assertStringNotContainsString($link, $textwithoutlink);
 260                      break;
 261  
 262                  default:
 263                      break;
 264              }
 265          }
 266      }
 267  
 268      /**
 269       * Test for embed_url.
 270       * Check SWF works including the special option required to enable it
 271       */
 272      public function test_embed_url_swf() {
 273          \core\plugininfo\media::set_enabled_plugins('swf');
 274          $manager = core_media_manager::instance();
 275  
 276          // Without any options...
 277          $url = new \moodle_url('http://example.org/test.swf');
 278          $t = $manager->embed_url($url);
 279          $this->assertStringNotContainsString('</object>', $t);
 280  
 281          // ...and with the 'no it's safe, I checked it' option.
 282          $url = new \moodle_url('http://example.org/test.swf');
 283          $t = $manager->embed_url($url, '', 0, 0, array(core_media_manager::OPTION_TRUSTED => true));
 284          $this->assertStringContainsString('</object>', $t);
 285      }
 286  
 287      /**
 288       * Same as test_embed_url MP3 test, but for slash arguments.
 289       */
 290      public function test_slash_arguments() {
 291  
 292          // Again we do not turn slasharguments actually on, because it has to
 293          // work regardless of the setting of that variable in case of handling
 294          // links created using previous setting.
 295  
 296          // Enable player.
 297          \core\plugininfo\media::set_enabled_plugins('html5audio');
 298          $manager = core_media_manager::instance();
 299  
 300          // Format: mp3.
 301          $url = new \moodle_url('http://example.org/pluginfile.php?file=x/y/z/test.mp3');
 302          $t = $manager->embed_url($url);
 303          $this->assertStringContainsString('</audio>', $t);
 304      }
 305  
 306      /**
 307       * Test for embed_url.
 308       * Checks the EMBED_OR_BLANK option.
 309       */
 310      public function test_embed_or_blank() {
 311          \core\plugininfo\media::set_enabled_plugins('html5audio');
 312          $manager = core_media_manager::instance();
 313          $this->pretend_to_be_firefox();
 314  
 315          $options = array(core_media_manager::OPTION_FALLBACK_TO_BLANK => true);
 316  
 317          // Embed that does match something should still include the link too.
 318          $url = new \moodle_url('http://example.org/test.ogg');
 319          $t = $manager->embed_url($url, '', 0, 0, $options);
 320          $this->assertStringContainsString('</audio>', $t);
 321          $this->assertStringContainsString('mediafallbacklink', $t);
 322  
 323          // Embed that doesn't match something should be totally blank.
 324          $url = new \moodle_url('http://example.org/test.mp4');
 325          $t = $manager->embed_url($url, '', 0, 0, $options);
 326          $this->assertSame('', $t);
 327      }
 328  
 329      /**
 330       * Test for embed_url.
 331       * Checks that size is passed through correctly to player objects and tests
 332       * size support in html5video output.
 333       */
 334      public function test_embed_url_size() {
 335          global $CFG;
 336  
 337          // Technically this could break in every format and they handle size
 338          // in several different ways, but I'm too lazy to test it in every
 339          // format, so let's just pick one to check the values get passed
 340          // through.
 341          \core\plugininfo\media::set_enabled_plugins('html5video');
 342          $manager = core_media_manager::instance();
 343          $url = new \moodle_url('http://example.org/test.mp4');
 344  
 345          // HTML5 default size - specifies core width and does not specify height.
 346          $t = $manager->embed_url($url);
 347          $this->assertStringContainsString('width="' . $CFG->media_default_width . '"', $t);
 348          $this->assertStringNotContainsString('height', $t);
 349  
 350          // HTML5 specified size - specifies both.
 351          $t = $manager->embed_url($url, '', '666', '101');
 352          $this->assertStringContainsString('width="666"', $t);
 353          $this->assertStringContainsString('height="101"', $t);
 354  
 355          // HTML5 size specified in url, overrides call.
 356          $url = new \moodle_url('http://example.org/test.mp4?d=123x456');
 357          $t = $manager->embed_url($url, '', '666', '101');
 358          $this->assertStringContainsString('width="123"', $t);
 359          $this->assertStringContainsString('height="456"', $t);
 360      }
 361  
 362      /**
 363       * Test for embed_url.
 364       * Checks that name is passed through correctly to player objects and tests
 365       * name support in html5video output.
 366       */
 367      public function test_embed_url_name() {
 368          // As for size this could break in every format but I'm only testing
 369          // html5video.
 370          \core\plugininfo\media::set_enabled_plugins('html5video');
 371          $manager = core_media_manager::instance();
 372          $url = new \moodle_url('http://example.org/test.mp4');
 373  
 374          // HTML5 default name - use filename.
 375          $t = $manager->embed_url($url);
 376          $this->assertStringContainsString('title="test.mp4"', $t);
 377  
 378          // HTML5 specified name - check escaping.
 379          $t = $manager->embed_url($url, 'frog & toad');
 380          $this->assertStringContainsString('title="frog &amp; toad"', $t);
 381      }
 382  
 383      /**
 384       * Test for split_alternatives.
 385       */
 386      public function test_split_alternatives() {
 387          $mediamanager = core_media_manager::instance();
 388  
 389          // Single URL - identical moodle_url.
 390          $mp4 = 'http://example.org/test.mp4';
 391          $result = $mediamanager->split_alternatives($mp4, $w, $h);
 392          $this->assertEquals($mp4, $result[0]->out(false));
 393  
 394          // Width and height weren't specified.
 395          $this->assertEquals(0, $w);
 396          $this->assertEquals(0, $h);
 397  
 398          // Two URLs - identical moodle_urls.
 399          $webm = 'http://example.org/test.webm';
 400          $result = $mediamanager->split_alternatives("$mp4#$webm", $w, $h);
 401          $this->assertEquals($mp4, $result[0]->out(false));
 402          $this->assertEquals($webm, $result[1]->out(false));
 403  
 404          // Two URLs plus dimensions.
 405          $size = 'd=400x280';
 406          $result = $mediamanager->split_alternatives("$mp4#$webm#$size", $w, $h);
 407          $this->assertEquals($mp4, $result[0]->out(false));
 408          $this->assertEquals($webm, $result[1]->out(false));
 409          $this->assertEquals(400, $w);
 410          $this->assertEquals(280, $h);
 411  
 412          // Two URLs plus legacy dimensions (use last one).
 413          $result = $mediamanager->split_alternatives("$mp4?d=1x1#$webm?$size", $w, $h);
 414          $this->assertEquals($mp4, $result[0]->out(false));
 415          $this->assertEquals($webm, $result[1]->out(false));
 416          $this->assertEquals(400, $w);
 417          $this->assertEquals(280, $h);
 418      }
 419  
 420      /**
 421       * Test for embed_alternatives (with multiple urls)
 422       */
 423      public function test_embed_alternatives() {
 424          // Most aspects of this are same as single player so let's just try
 425          // a single typical / complicated scenario.
 426  
 427          // MP4, OGV, WebM and FLV.
 428          $urls = array(
 429              new \moodle_url('http://example.org/test.mp4'),
 430              new \moodle_url('http://example.org/test.ogv'),
 431              new \moodle_url('http://example.org/test.webm'),
 432              new \moodle_url('http://example.org/test.flv'),
 433          );
 434  
 435          // Enable html5 and "test" ("test" first).
 436          \core\plugininfo\media::set_enabled_plugins('test,html5video');
 437          $manager = core_media_manager::instance();
 438  
 439          // Result should contain HTML5 with two sources + FLV.
 440          $t = $manager->embed_alternatives($urls);
 441  
 442          // HTML5 sources - mp4, but not ogv, flv or webm (not supported in Safari).
 443          $this->assertStringContainsString('<source src="http://example.org/test.mp4"', $t);
 444          $this->assertStringNotContainsString('<source src="http://example.org/test.ogv"', $t);
 445          $this->assertStringNotContainsString('<source src="http://example.org/test.webm"', $t);
 446          $this->assertStringNotContainsString('<source src="http://example.org/test.flv"', $t);
 447  
 448          // FLV is before the video tag (indicating html5 is used as fallback to flv
 449          // and not vice versa).
 450          $this->assertTrue((bool)preg_match('~mediaplugin_test.*<video~s', $t));
 451  
 452          // Do same test with firefox and check we get the webm and not mp4.
 453          $this->pretend_to_be_firefox();
 454          $t = $manager->embed_alternatives($urls);
 455  
 456          // HTML5 sources - mp4, ogv and webm, but not flv.
 457          $this->assertStringContainsString('<source src="http://example.org/test.mp4"', $t);
 458          $this->assertStringContainsString('<source src="http://example.org/test.ogv"', $t);
 459          $this->assertStringContainsString('<source src="http://example.org/test.webm"', $t);
 460          $this->assertStringNotContainsString('<source src="http://example.org/test.flv"', $t);
 461      }
 462  
 463      /**
 464       * Make sure the instance() method returns singleton for the same page and different object for another page
 465       */
 466      public function test_initialise() {
 467          $moodlepage1 = new \moodle_page();
 468  
 469          $mediamanager1 = core_media_manager::instance($moodlepage1);
 470          $mediamanager2 = core_media_manager::instance($moodlepage1);
 471  
 472          $this->assertSame($mediamanager1, $mediamanager2);
 473  
 474          $moodlepage3 = new \moodle_page();
 475          $mediamanager3 = core_media_manager::instance($moodlepage3);
 476  
 477          $this->assertNotSame($mediamanager1, $mediamanager3);
 478      }
 479  
 480  
 481      /**
 482       * Access list of players as string, shortening it by getting rid of
 483       * repeated text.
 484       * @param core_media_manager $manager The core_media_manager instance
 485       * @return string Comma-separated list of players
 486       */
 487      public function get_players_test($manager) {
 488          $method = new \ReflectionMethod("core_media_manager", "get_players");
 489          $method->setAccessible(true);
 490          $players = $method->invoke($manager);
 491          $out = '';
 492          foreach ($players as $player) {
 493              if ($out) {
 494                  $out .= ', ';
 495              }
 496              $out .= str_replace('core_media_player_', '', preg_replace('/^media_(.*)_plugin$/', '$1', get_class($player)));
 497          }
 498          return $out;
 499      }
 500  }