PageRenderTime 65ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/moodle/filter/mediaplugin/filter.php

#
PHP | 914 lines | 579 code | 154 blank | 181 comment | 75 complexity | b1343f6fca23c20443c04a26e3d7a54b MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, BSD-3-Clause, AGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, Apache-2.0
  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. * Media plugin filtering
  18. *
  19. * This filter will replace any links to a media file with
  20. * a media plugin that plays that media inline
  21. *
  22. * @package filter
  23. * @subpackage mediaplugin
  24. * @copyright 2004 onwards Martin Dougiamas {@link http://moodle.com}
  25. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  26. */
  27. defined('MOODLE_INTERNAL') || die();
  28. require_once($CFG->libdir.'/filelib.php');
  29. if (!defined('FILTER_MEDIAPLUGIN_VIDEO_WIDTH')) {
  30. /**
  31. * Default media width, some plugins may use automatic sizes or accept resize parameters.
  32. * This can be defined in config.php.
  33. */
  34. define('FILTER_MEDIAPLUGIN_VIDEO_WIDTH', 400);
  35. }
  36. if (!defined('FILTER_MEDIAPLUGIN_VIDEO_HEIGHT')) {
  37. /**
  38. * Default video height, plugins that know aspect ration
  39. * should calculate it themselves using the FILTER_MEDIAPLUGIN_VIDEO_HEIGHT
  40. * This can be defined in config.php.
  41. */
  42. define('FILTER_MEDIAPLUGIN_VIDEO_HEIGHT', 300);
  43. }
  44. //TODO: we should use /u modifier in regex, unfortunately it may not work properly on some misconfigured servers, see lib/filter/urltolink/filter.php ...
  45. //TODO: we should migrate to proper config_plugin settings ...
  46. /**
  47. * Automatic media embedding filter class.
  48. *
  49. * It is highly recommended to configure servers to be compatible with our slasharguments,
  50. * otherwise the "?d=600x400" may not work.
  51. *
  52. * @package filter
  53. * @subpackage mediaplugin
  54. * @copyright 2004 onwards Martin Dougiamas {@link http://moodle.com}
  55. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  56. */
  57. class filter_mediaplugin extends moodle_text_filter {
  58. function filter($text, array $options = array()) {
  59. global $CFG;
  60. if (!is_string($text) or empty($text)) {
  61. // non string data can not be filtered anyway
  62. return $text;
  63. }
  64. if (stripos($text, '</a>') === false) {
  65. // performance shortcut - all regexes below end with the </a> tag,
  66. // if not present nothing can match
  67. return $text;
  68. }
  69. $newtext = $text; // we need to return the original value if regex fails!
  70. // YouTube and Vimeo are great because the files are not served by Moodle server
  71. if (!empty($CFG->filter_mediaplugin_enable_youtube)) {
  72. $search = '/<a\s[^>]*href="(https?:\/\/www\.youtube(-nocookie)?\.com)\/watch\?v=([a-z0-9\-_]+)[^"#]*(#d=([\d]{1,4})x([\d]{1,4}))?"[^>]*>([^>]*)<\/a>/is';
  73. $newtext = preg_replace_callback($search, 'filter_mediaplugin_youtube_callback', $newtext);
  74. $search = '/<a\s[^>]*href="(https?:\/\/www\.youtube(-nocookie)?\.com)\/v\/([a-z0-9\-_]+)[^"#]*(#d=([\d]{1,4})x([\d]{1,4}))?[^>]*>([^>]*)<\/a>/is';
  75. $newtext = preg_replace_callback($search, 'filter_mediaplugin_youtube_callback', $newtext);
  76. $search = '/<a\s[^>]*href="(https?:\/\/www\.youtube(-nocookie)?\.com)\/view_play_list\?p=([a-z0-9\-_]+)[^"#]*(#d=([\d]{1,4})x([\d]{1,4}))?[^>]*>([^>]*)<\/a>/is';
  77. $newtext = preg_replace_callback($search, 'filter_mediaplugin_youtube_playlist_callback', $newtext);
  78. $search = '/<a\s[^>]*href="(https?:\/\/www\.youtube(-nocookie)?\.com)\/p\/([a-z0-9\-_]+)[^"#]*(#d=([\d]{1,4})x([\d]{1,4}))?[^>]*>([^>]*)<\/a>/is';
  79. $newtext = preg_replace_callback($search, 'filter_mediaplugin_youtube_playlist_callback', $newtext);
  80. }
  81. if (!empty($CFG->filter_mediaplugin_enable_vimeo)) {
  82. $search = '/<a\s[^>]*href="http:\/\/vimeo\.com\/([0-9]+)[^"#]*(#d=([\d]{1,4})x([\d]{1,4}))?[^>]*>([^>]*)<\/a>/is';
  83. $newtext = preg_replace_callback($search, 'filter_mediaplugin_vimeo_callback', $newtext);
  84. }
  85. // HTML 5 audio and video tags are the future! If only if vendors decided to use just one audio and video format...
  86. if (!empty($CFG->filter_mediaplugin_enable_html5audio)) {
  87. $search = '/<a\s[^>]*href="([^"#\?]+\.(ogg|oga|aac|m4a)([#\?][^"]*)?)"[^>]*>([^>]*)<\/a>/is';
  88. $newtext = preg_replace_callback($search, 'filter_mediaplugin_html5audio_callback', $newtext);
  89. }
  90. if (!empty($CFG->filter_mediaplugin_enable_html5video)) {
  91. $search = '/<a\s[^>]*href="([^"#\?]+\.(m4v|webm|ogv|mp4)([#\?][^"]*)?)"[^>]*>([^>]*)<\/a>/is';
  92. $newtext = preg_replace_callback($search, 'filter_mediaplugin_html5video_callback', $newtext);
  93. }
  94. // Flash stuff
  95. if (!empty($CFG->filter_mediaplugin_enable_mp3)) {
  96. $search = '/<a\s[^>]*href="([^"#\?]+\.mp3)"[^>]*>([^>]*)<\/a>/is';
  97. $newtext = preg_replace_callback($search, 'filter_mediaplugin_mp3_callback', $newtext);
  98. }
  99. if ((!empty($options['noclean']) or !empty($CFG->allowobjectembed)) and !empty($CFG->filter_mediaplugin_enable_swf)) {
  100. $search = '/<a\s[^>]*href="([^"#\?]+\.swf)([#\?]d=([\d]{1,4})x([\d]{1,4}))?"[^>]*>([^>]*)<\/a>/is';
  101. $newtext = preg_replace_callback($search, 'filter_mediaplugin_swf_callback', $newtext);
  102. }
  103. if (!empty($CFG->filter_mediaplugin_enable_flv)) {
  104. $search = '/<a\s[^>]*href="([^"#\?]+\.(flv|f4v)([#\?][^"]*)?)"[^>]*>([^>]*)<\/a>/is';
  105. $newtext = preg_replace_callback($search, 'filter_mediaplugin_flv_callback', $newtext);
  106. }
  107. // The rest of legacy formats - these should not be used if possible
  108. if (!empty($CFG->filter_mediaplugin_enable_wmp)) {
  109. $search = '/<a\s[^>]*href="([^"#\?]+\.(wmv|avi))(\?d=([\d]{1,4})x([\d]{1,4}))?"[^>]*>([^>]*)<\/a>/is';
  110. $newtext = preg_replace_callback($search, 'filter_mediaplugin_wmp_callback', $newtext);
  111. }
  112. if (!empty($CFG->filter_mediaplugin_enable_qt)) {
  113. // HTML5 filtering may steal mpeg 4 formats
  114. $search = '/<a\s[^>]*href="([^"#\?]+\.(mpg|mpeg|mov|mp4|m4v|m4a))(\?d=([\d]{1,4})x([\d]{1,4}))?"[^>]*>([^>]*)<\/a>/is';
  115. $newtext = preg_replace_callback($search, 'filter_mediaplugin_qt_callback', $newtext);
  116. }
  117. if (!empty($CFG->filter_mediaplugin_enable_rm)) {
  118. // hopefully nobody is using this any more!!
  119. // rpm is redhat packaging format these days, it is better to prevent these in default installs
  120. $search = '/<a\s[^>]*href="([^"#\?]+\.(ra|ram|rm|rv))"[^>]*>([^>]*)<\/a>/is';
  121. $newtext = preg_replace_callback($search, 'filter_mediaplugin_real_callback', $newtext);
  122. }
  123. if (empty($newtext) or $newtext === $text) {
  124. // error or not filtered
  125. unset($newtext);
  126. return $text;
  127. }
  128. return $newtext;
  129. }
  130. }
  131. ///===========================
  132. /// utility functions
  133. /**
  134. * Get mimetype of given url, useful for # alternative urls.
  135. *
  136. * @private
  137. * @param string $url
  138. * @return string $mimetype
  139. */
  140. function filter_mediaplugin_get_mimetype($url) {
  141. $matches = null;
  142. if (preg_match("|^(.*)/[a-z]*file.php(\?file=)?(/[^&\?#]*)|", $url, $matches)) {
  143. // remove the special moodle file serving hacks so that the *file.php is ignored
  144. $url = $matches[1].$matches[3];
  145. } else {
  146. $url = preg_replace('/[#\?].*$/', '', $url);
  147. }
  148. $mimetype = mimeinfo('type', $url);
  149. return $mimetype;
  150. }
  151. /**
  152. * Parse list of alternative URLs
  153. * @param string $url urls separated with '#', size specified as ?d=640x480 or #d=640x480
  154. * @param int $defaultwidth
  155. * @param int $defaultheight
  156. * @return array (urls, width, height)
  157. */
  158. function filter_mediaplugin_parse_alternatives($url, $defaultwidth = 0, $defaultheight = 0) {
  159. $urls = explode('#', $url);
  160. $width = $defaultwidth;
  161. $height = $defaultheight;
  162. $returnurls = array();
  163. foreach ($urls as $url) {
  164. $matches = null;
  165. if (preg_match('/^d=([\d]{1,4})x([\d]{1,4})$/i', $url, $matches)) { // #d=640x480
  166. $width = $matches[1];
  167. $height = $matches[2];
  168. continue;
  169. }
  170. if (preg_match('/\?d=([\d]{1,4})x([\d]{1,4})$/i', $url, $matches)) { // old style file.ext?d=640x480
  171. $width = $matches[1];
  172. $height = $matches[2];
  173. $url = str_replace($matches[0], '', $url);
  174. }
  175. $url = str_replace('&amp;', '&', $url);
  176. $url = clean_param($url, PARAM_URL);
  177. if (empty($url)) {
  178. continue;
  179. }
  180. $returnurls[] = $url;
  181. }
  182. return array($returnurls, $width, $height);
  183. }
  184. /**
  185. * Should the current tag be ignored in this filter?
  186. * @param string $tag
  187. * @return bool
  188. */
  189. function filter_mediaplugin_ignore($tag) {
  190. if (preg_match('/class="[^"]*nomediaplugin/i', $tag)) {
  191. return true;
  192. } else {
  193. false;
  194. }
  195. }
  196. ///===========================
  197. /// callback filter functions
  198. /**
  199. * Replace audio links with audio tag.
  200. *
  201. * @param array $link
  202. * @return string
  203. */
  204. function filter_mediaplugin_html5audio_callback(array $link) {
  205. global $CFG;
  206. if (filter_mediaplugin_ignore($link[0])) {
  207. return $link[0];
  208. }
  209. $info = trim($link[4]);
  210. if (empty($info) or strpos($info, 'http') === 0) {
  211. $info = get_string('fallbackaudio', 'filter_mediaplugin');
  212. }
  213. list($urls, $ignorewidth, $ignoredheight) = filter_mediaplugin_parse_alternatives($link[1]);
  214. $fallbackurl = null;
  215. $fallbackmime = null;
  216. $sources = array();
  217. $fallbacklink = null;
  218. foreach ($urls as $url) {
  219. $mimetype = filter_mediaplugin_get_mimetype($url);
  220. if (strpos($mimetype, 'audio/') !== 0) {
  221. continue;
  222. }
  223. $sources[] = html_writer::tag('source', '', array('src' => $url, 'type' => $mimetype));
  224. if ($fallbacklink === null) {
  225. $fallbacklink = html_writer::link($url.'#', $info); // the extra '#' prevents linking in mp3 filter below
  226. }
  227. if ($fallbackurl === null) {
  228. if ($mimetype === 'audio/mp3' or $mimetype === 'audio/aac') {
  229. $fallbackurl = str_replace('&', '&amp;', $url);
  230. $fallbackmime = $mimetype;
  231. }
  232. }
  233. }
  234. if (!$sources) {
  235. return $link[0];
  236. }
  237. if ($fallbackmime !== null) {
  238. // fallback to quicktime
  239. $fallback = <<<OET
  240. <object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab" width="200" height="20">
  241. <param name="pluginspage" value="http://www.apple.com/quicktime/download/" />
  242. <param name="src" value="$fallbackurl" />
  243. <param name="controller" value="true" />
  244. <param name="loop" value="false" />
  245. <param name="autoplay" value="false" />
  246. <param name="autostart" value="false" />
  247. <param name="scale" value="aspect" />
  248. $fallbacklink
  249. <!--[if !IE]>-->
  250. <object data="$fallbackurl" type="$fallbackmime" width="200" height="20">
  251. <param name="src" value="$fallbackurl" />
  252. <param name="pluginurl" value="http://www.apple.com/quicktime/download/" />
  253. <param name="controller" value="true" />
  254. <param name="loop" value="false" />
  255. <param name="autoplay" value="false" />
  256. <param name="autostart" value="false" />
  257. <param name="scale" value="aspect" />
  258. $fallbacklink
  259. </object>
  260. <!--<![endif]-->
  261. </object>
  262. OET;
  263. } else {
  264. $fallback = $fallbacklink;
  265. }
  266. $sources = implode("\n", $sources);
  267. $title = s($info);
  268. // audio players are supposed to be inline elements
  269. $output = <<<OET
  270. <audio controls="true" width="200" class="mediaplugin mediaplugin_html5audio" preload="no" title="$title">
  271. $sources
  272. $fallback
  273. </audio>
  274. OET;
  275. return $output;
  276. }
  277. /**
  278. * Replace ogg video links with video tag.
  279. *
  280. * Please note this is not going to work in all browsers,
  281. * it is also not xhtml strict.
  282. *
  283. * @param array $link
  284. * @return string
  285. */
  286. function filter_mediaplugin_html5video_callback(array $link) {
  287. if (filter_mediaplugin_ignore($link[0])) {
  288. return $link[0];
  289. }
  290. $info = trim($link[4]);
  291. if (empty($info) or strpos($info, 'http') === 0) {
  292. $info = get_string('fallbackvideo', 'filter_mediaplugin');
  293. }
  294. list($urls, $width, $height) = filter_mediaplugin_parse_alternatives($link[1], FILTER_MEDIAPLUGIN_VIDEO_WIDTH, 0);
  295. $fallbackurl = null;
  296. $fallbackmime = null;
  297. $sources = array();
  298. $fallbacklink = null;
  299. foreach ($urls as $url) {
  300. $mimetype = filter_mediaplugin_get_mimetype($url);
  301. if (strpos($mimetype, 'video/') !== 0) {
  302. continue;
  303. }
  304. $source = html_writer::tag('source', '', array('src' => $url, 'type' => $mimetype));
  305. if ($mimetype === 'video/mp4') {
  306. // better add m4v as first source, it might be a bit more compatible with problematic browsers
  307. array_unshift($sources, $source);
  308. } else {
  309. $sources[] = $source;
  310. }
  311. if ($fallbacklink === null) {
  312. $fallbacklink = html_writer::link($url.'#', $info); // the extra '#' prevents linking in mp3 filter below
  313. }
  314. if ($fallbackurl === null) {
  315. if ($mimetype === 'video/mp4') {
  316. $fallbackurl = str_replace('&', '&amp;', $url);
  317. $fallbackmime = $mimetype;
  318. }
  319. }
  320. }
  321. if (!$sources) {
  322. return $link[0];
  323. }
  324. if ($fallbackmime !== null) {
  325. $qtheight = ($height == 0) ? FILTER_MEDIAPLUGIN_VIDEO_HEIGHT : ($height + 15);
  326. // fallback to quicktime
  327. $fallback = <<<OET
  328. <object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab" width="$width" height="$qtheight">
  329. <param name="pluginspage" value="http://www.apple.com/quicktime/download/" />
  330. <param name="src" value="$fallbackurl" />
  331. <param name="controller" value="true" />
  332. <param name="loop" value="false" />
  333. <param name="autoplay" value="false" />
  334. <param name="autostart" value="false" />
  335. <param name="scale" value="aspect" />
  336. $fallbacklink
  337. <!--[if !IE]>-->
  338. <object data="$fallbackurl" type="$fallbackmime" width="$width" height="$qtheight">
  339. <param name="src" value="$fallbackurl" />
  340. <param name="pluginurl" value="http://www.apple.com/quicktime/download/" />
  341. <param name="controller" value="true" />
  342. <param name="loop" value="false" />
  343. <param name="autoplay" value="false" />
  344. <param name="autostart" value="false" />
  345. <param name="scale" value="aspect" />
  346. $fallbacklink
  347. </object>
  348. <!--<![endif]-->
  349. </object>
  350. OET;
  351. } else {
  352. $fallback = $fallbacklink;
  353. }
  354. $sources = implode("\n", $sources);
  355. $title = s($info);
  356. if (empty($height)) {
  357. // automatic height
  358. $size = "width=\"$width\"";
  359. } else {
  360. $size = "width=\"$width\" height=\"$height\"";
  361. }
  362. $output = <<<OET
  363. <span class="mediaplugin mediaplugin_html5video">
  364. <video controls="true" $size preload="metadata" title="$title">
  365. $sources
  366. $fallback
  367. </video>
  368. </span>
  369. OET;
  370. return $output;
  371. }
  372. /**
  373. * Replace mp3 links with small audio player.
  374. *
  375. * @param $link
  376. * @return string
  377. */
  378. function filter_mediaplugin_mp3_callback($link) {
  379. static $count = 0;
  380. if (filter_mediaplugin_ignore($link[0])) {
  381. return $link[0];
  382. }
  383. $count++;
  384. $id = 'filter_mp3_'.time().'_'.$count; //we need something unique because it might be stored in text cache
  385. $url = $link[1];
  386. $rawurl = str_replace('&amp;', '&', $url);
  387. $info = trim($link[2]);
  388. if (empty($info) or strpos($info, 'http') === 0) {
  389. $info = get_string('mp3audio', 'filter_mediaplugin');
  390. }
  391. $printlink = html_writer::link($rawurl, $info, array('class'=>'mediafallbacklink'));
  392. //note: when flash or javascript not available only the $printlink is displayed,
  393. // audio players are supposed to be inline elements
  394. $output = html_writer::tag('span', $printlink, array('id'=>$id, 'class'=>'mediaplugin mediaplugin_mp3'));
  395. $output .= html_writer::script(js_writer::function_call('M.util.add_audio_player', array($id, $rawurl, true))); // we can not use standard JS init because this may be cached
  396. return $output;
  397. }
  398. /**
  399. * Replace swf links with embedded flash objects.
  400. *
  401. * Please note this is not a secure and is recommended to be disabled on production systems.
  402. *
  403. * @deprecated
  404. * @param $link
  405. * @return string
  406. */
  407. function filter_mediaplugin_swf_callback($link) {
  408. if (filter_mediaplugin_ignore($link[0])) {
  409. return $link[0];
  410. }
  411. $width = empty($link[3]) ? FILTER_MEDIAPLUGIN_VIDEO_WIDTH : $link[3];
  412. $height = empty($link[4]) ? FILTER_MEDIAPLUGIN_VIDEO_HEIGHT : $link[4];
  413. $url = $link[1];
  414. $rawurl = str_replace('&amp;', '&', $url);
  415. $info = trim($link[5]);
  416. if (empty($info) or strpos($info, 'http') === 0) {
  417. $info = get_string('flashanimation', 'filter_mediaplugin');
  418. }
  419. $printlink = html_writer::link($rawurl, $info, array('class'=>'mediafallbacklink'));
  420. $output = <<<OET
  421. <span class="mediaplugin mediaplugin_swf">
  422. <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="$width" height="$height">
  423. <param name="movie" value="$url" />
  424. <param name="autoplay" value="true" />
  425. <param name="loop" value="true" />
  426. <param name="controller" value="true" />
  427. <param name="scale" value="aspect" />
  428. <param name="base" value="." />
  429. <param name="allowscriptaccess" value="never" />
  430. <!--[if !IE]>-->
  431. <object type="application/x-shockwave-flash" data="$url" width="$width" height="$height">
  432. <param name="controller" value="true" />
  433. <param name="autoplay" value="true" />
  434. <param name="loop" value="true" />
  435. <param name="scale" value="aspect" />
  436. <param name="base" value="." />
  437. <param name="allowscriptaccess" value="never" />
  438. <!--<![endif]-->
  439. $printlink
  440. <!--[if !IE]>-->
  441. </object>
  442. <!--<![endif]-->
  443. </object>
  444. </span>
  445. OET;
  446. return $output;
  447. }
  448. /**
  449. * Replace flv links with flow player.
  450. *
  451. * @param $link
  452. * @return string
  453. */
  454. function filter_mediaplugin_flv_callback($link) {
  455. static $count = 0;
  456. if (filter_mediaplugin_ignore($link[0])) {
  457. return $link[0];
  458. }
  459. $count++;
  460. $id = 'filter_flv_'.time().'_'.$count; //we need something unique because it might be stored in text cache
  461. list($urls, $width, $height) = filter_mediaplugin_parse_alternatives($link[1], 0, 0);
  462. $autosize = false;
  463. if (!$width and !$height) {
  464. $width = FILTER_MEDIAPLUGIN_VIDEO_WIDTH;
  465. $height = FILTER_MEDIAPLUGIN_VIDEO_HEIGHT;
  466. $autosize = true;
  467. }
  468. $flashurl = null;
  469. $sources = array();
  470. foreach ($urls as $url) {
  471. $mimetype = filter_mediaplugin_get_mimetype($url);
  472. if (strpos($mimetype, 'video/') !== 0) {
  473. continue;
  474. }
  475. $source = html_writer::tag('source', '', array('src' => $url, 'type' => $mimetype));
  476. if ($mimetype === 'video/mp4') {
  477. // better add m4v as first source, it might be a bit more compatible with problematic browsers
  478. array_unshift($sources, $source);
  479. } else {
  480. $sources[] = $source;
  481. }
  482. if ($flashurl === null) {
  483. $flashurl = $url;
  484. }
  485. }
  486. if (!$sources) {
  487. return $link[0];
  488. }
  489. $info = trim($link[4]);
  490. if (empty($info) or strpos($info, 'http') === 0) {
  491. $info = get_string('fallbackvideo', 'filter_mediaplugin');
  492. }
  493. $printlink = html_writer::link($flashurl.'#', $info, array('class'=>'mediafallbacklink')); // the '#' prevents the QT filter
  494. $title = s($info);
  495. if (count($sources) > 1) {
  496. $sources = implode("\n", $sources);
  497. // html 5 fallback
  498. $printlink = <<<OET
  499. <video controls="true" width="$width" height="$height" preload="metadata" title="$title">
  500. $sources
  501. $printlink
  502. </video>
  503. <noscript><br />
  504. $printlink
  505. </noscript>
  506. OET;
  507. }
  508. // note: no need to print "this is flv link" because it is printed automatically if JS or Flash not available
  509. $output = html_writer::tag('span', $printlink, array('id'=>$id, 'class'=>'mediaplugin mediaplugin_flv'));
  510. $output .= html_writer::script(js_writer::function_call('M.util.add_video_player', array($id, rawurlencode($flashurl), $width, $height, $autosize))); // we can not use standard JS init because this may be cached
  511. return $output;
  512. }
  513. /**
  514. * Replace real media links with real player.
  515. *
  516. * Note: hopefully nobody is using this obsolete format any more.
  517. *
  518. * @deprectated
  519. * @param $link
  520. * @return string
  521. */
  522. function filter_mediaplugin_real_callback($link) {
  523. if (filter_mediaplugin_ignore($link[0])) {
  524. return $link[0];
  525. }
  526. $url = $link[1];
  527. $rawurl = str_replace('&amp;', '&', $url);
  528. //Note: the size is hardcoded intentionally because this does not work anyway!
  529. $width = FILTER_MEDIAPLUGIN_VIDEO_WIDTH;
  530. $height = FILTER_MEDIAPLUGIN_VIDEO_HEIGHT;
  531. $info = trim($link[3]);
  532. if (empty($info) or strpos($info, 'http') === 0) {
  533. $info = get_string('fallbackvideo', 'filter_mediaplugin');
  534. }
  535. $printlink = html_writer::link($rawurl, $info, array('class'=>'mediafallbacklink'));
  536. return <<<OET
  537. <span class="mediaplugin mediaplugin_real">
  538. $printlink <br />
  539. <object title="$info" classid="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" data="$url" width="$width" height="$height"">
  540. <param name="src" value="$url" />
  541. <param name="controls" value="All" />
  542. <!--[if !IE]>-->
  543. <object title="$info" type="audio/x-pn-realaudio-plugin" data="$url" width="$width" height="$height">
  544. <param name="src" value="$url" />
  545. <param name="controls" value="All" />
  546. <!--<![endif]-->
  547. <!--[if !IE]>-->
  548. </object>
  549. <!--<![endif]-->
  550. </object>
  551. </span>
  552. OET;
  553. }
  554. /**
  555. * Change links to YouTube into embedded YouTube videos
  556. *
  557. * Note: resizing via url is not supported, user can click the fullscreen button instead
  558. *
  559. * @param $link
  560. * @return string
  561. */
  562. function filter_mediaplugin_youtube_callback($link) {
  563. global $CFG;
  564. if (filter_mediaplugin_ignore($link[0])) {
  565. return $link[0];
  566. }
  567. $site = $link[1];
  568. $videoid = $link[3];
  569. $info = trim($link[7]);
  570. if (empty($info) or strpos($info, 'http') === 0) {
  571. $info = get_string('siteyoutube', 'filter_mediaplugin');
  572. }
  573. $info = s($info);
  574. $width = empty($link[5]) ? FILTER_MEDIAPLUGIN_VIDEO_WIDTH : $link[5];
  575. $height = empty($link[6]) ? FILTER_MEDIAPLUGIN_VIDEO_HEIGHT : $link[6];
  576. if (empty($CFG->xmlstrictheaders)) {
  577. return <<<OET
  578. <iframe title="$info" width="$width" height="$height" src="$site/embed/$videoid?rel=0" frameborder="0" allowfullscreen></iframe>
  579. OET;
  580. }
  581. //NOTE: we can not use any link fallback because it breaks built-in player on iOS devices
  582. $output = <<<OET
  583. <span class="mediaplugin mediaplugin_youtube">
  584. <object title="$info" type="application/x-shockwave-flash" data="$site/v/$videoid&amp;fs=1&amp;rel=0" width="$width" height="$height">
  585. <param name="movie" value="$site/v/$videoid&amp;fs=1&amp;rel=0" />
  586. <param name="FlashVars" value="playerMode=embedded" />
  587. <param name="allowFullScreen" value="true" />
  588. </object>
  589. </span>
  590. OET;
  591. return $output;
  592. }
  593. /**
  594. * Change YouTube playlist into embedded YouTube playlist videos
  595. *
  596. * Note: resizing via url is not supported, user can click the fullscreen button instead
  597. *
  598. * @param $link
  599. * @return string
  600. */
  601. function filter_mediaplugin_youtube_playlist_callback($link) {
  602. global $CFG;
  603. if (filter_mediaplugin_ignore($link[0])) {
  604. return $link[0];
  605. }
  606. $site = $link[1];
  607. $playlist = $link[3];
  608. $info = trim($link[7]);
  609. if (empty($info) or strpos($info, 'http') === 0) {
  610. $info = get_string('siteyoutube', 'filter_mediaplugin');
  611. }
  612. $printlink = html_writer::link("$site/view_play_list\?p=$playlist", $info, array('class'=>'mediafallbacklink'));
  613. $info = s($info);
  614. $width = empty($link[5]) ? FILTER_MEDIAPLUGIN_VIDEO_WIDTH : $link[5];
  615. $height = empty($link[6]) ? FILTER_MEDIAPLUGIN_VIDEO_HEIGHT : $link[6];
  616. // TODO: iframe HTML 5 video not implemented and object does work on iOS devices
  617. $output = <<<OET
  618. <span class="mediaplugin mediaplugin_youtube">
  619. <object title="$info" type="application/x-shockwave-flash" data="$site/p/$playlist&amp;fs=1&amp;rel=0" width="$width" height="$height">
  620. <param name="movie" value="$site/v/$playlist&amp;fs=1&amp;rel=0" />
  621. <param name="FlashVars" value="playerMode=embedded" />
  622. <param name="allowFullScreen" value="true" />
  623. $printlink</object>
  624. </span>
  625. OET;
  626. return $output;
  627. }
  628. /**
  629. * Change links to Vimeo into embedded Vimeo videos
  630. *
  631. * @param $link
  632. * @return string
  633. */
  634. function filter_mediaplugin_vimeo_callback($link) {
  635. global $CFG;
  636. if (filter_mediaplugin_ignore($link[0])) {
  637. return $link[0];
  638. }
  639. $videoid = $link[1];
  640. $info = s(strip_tags($link[5]));
  641. //Note: resizing via url is not supported, user can click the fullscreen button instead
  642. // iframe embedding is not xhtml strict but it is the only option that seems to work on most devices
  643. $width = empty($link[3]) ? FILTER_MEDIAPLUGIN_VIDEO_WIDTH : $link[3];
  644. $height = empty($link[4]) ? FILTER_MEDIAPLUGIN_VIDEO_HEIGHT : $link[4];
  645. $output = <<<OET
  646. <span class="mediaplugin mediaplugin_vimeo">
  647. <iframe title="$info" src="http://player.vimeo.com/video/$videoid" width="$width" height="$height" frameborder="0"></iframe>
  648. </span>
  649. OET;
  650. return $output;
  651. }
  652. /**
  653. * Embed video using window media player if available
  654. *
  655. * This does not work much outside of IE, hopefully not many ppl use it these days.
  656. *
  657. * @param $link
  658. * @return string
  659. */
  660. function filter_mediaplugin_wmp_callback($link) {
  661. if (filter_mediaplugin_ignore($link[0])) {
  662. return $link[0];
  663. }
  664. $url = $link[1];
  665. $rawurl = str_replace('&amp;', '&', $url);
  666. $info = trim($link[6]);
  667. if (empty($info) or strpos($info, 'http') === 0) {
  668. $info = get_string('fallbackvideo', 'filter_mediaplugin');
  669. }
  670. $printlink = html_writer::link($rawurl, $info, array('class'=>'mediafallbacklink'));
  671. if (empty($link[4]) or empty($link[5])) {
  672. $mpsize = '';
  673. $size = 'width="'.FILTER_MEDIAPLUGIN_VIDEO_WIDTH.'" height="'.(FILTER_MEDIAPLUGIN_VIDEO_HEIGHT+64).'"';
  674. $autosize = 'true';
  675. } else {
  676. $size = 'width="'.$link[4].'" height="'.($link[5] + 15).'"';
  677. $mpsize = 'width="'.$link[4].'" height="'.($link[5] + 64).'"';
  678. $autosize = 'false';
  679. }
  680. $mimetype = filter_mediaplugin_get_mimetype($url);
  681. return <<<OET
  682. <span class="mediaplugin mediaplugin_wmp">
  683. $printlink <br />
  684. <object classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6" $mpsize standby="Loading Microsoft(R) Windows(R) Media Player components..." type="application/x-oleobject">
  685. <param name="Filename" value="$url" />
  686. <param name="src" value="$url" />
  687. <param name="url" value="$url" />
  688. <param name="ShowControls" value="true" />
  689. <param name="AutoRewind" value="true" />
  690. <param name="AutoStart" value="false" />
  691. <param name="Autosize" value="$autosize" />
  692. <param name="EnableContextMenu" value="true" />
  693. <param name="TransparentAtStart" value="false" />
  694. <param name="AnimationAtStart" value="false" />
  695. <param name="ShowGotoBar" value="false" />
  696. <param name="EnableFullScreenControls" value="true" />
  697. <param name="uimode" value="full" />
  698. <!--[if !IE]>-->
  699. <object data="$url" type="$mimetype" $size>
  700. <param name="src" value="$url" />
  701. <param name="controller" value="true" />
  702. <param name="autoplay" value="false" />
  703. <param name="autostart" value="false" />
  704. <param name="resize" value="scale" />
  705. </object>
  706. <!--<![endif]-->
  707. </object></span>
  708. OET;
  709. }
  710. /**
  711. * Replace quicktime links with quicktime player.
  712. *
  713. * You need to install a quicktime player, it is not available for all browsers+OS combinations.
  714. *
  715. * @param $link
  716. * @return string
  717. */
  718. function filter_mediaplugin_qt_callback($link) {
  719. if (filter_mediaplugin_ignore($link[0])) {
  720. return $link[0];
  721. }
  722. $url = $link[1];
  723. $rawurl = str_replace('&amp;', '&', $url);
  724. $info = trim($link[6]);
  725. if (empty($info) or strpos($info, 'http') === 0) {
  726. $info = get_string('fallbackvideo', 'filter_mediaplugin');
  727. }
  728. $printlink = html_writer::link($rawurl, $info, array('class'=>'mediafallbacklink'));
  729. if (empty($link[4]) or empty($link[5])) {
  730. $size = 'width="'.FILTER_MEDIAPLUGIN_VIDEO_WIDTH.'" height="'.(FILTER_MEDIAPLUGIN_VIDEO_HEIGHT+15).'"';
  731. } else {
  732. $size = 'width="'.$link[4].'" height="'.($link[5]+15).'"';
  733. }
  734. $mimetype = filter_mediaplugin_get_mimetype($url);
  735. // this is the safest fallback for incomplete or missing browser support for this format
  736. return <<<OET
  737. <span class="mediaplugin mediaplugin_qt">
  738. $printlink <br />
  739. <object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab" $size>
  740. <param name="pluginspage" value="http://www.apple.com/quicktime/download/" />
  741. <param name="src" value="$url" />
  742. <param name="controller" value="true" />
  743. <param name="loop" value="true" />
  744. <param name="autoplay" value="false" />
  745. <param name="autostart" value="false" />
  746. <param name="scale" value="aspect" />
  747. <!--[if !IE]>-->
  748. <object data="$url" type="$mimetype" $size>
  749. <param name="src" value="$url" />
  750. <param name="pluginurl" value="http://www.apple.com/quicktime/download/" />
  751. <param name="controller" value="true" />
  752. <param name="loop" value="true" />
  753. <param name="autoplay" value="false" />
  754. <param name="autostart" value="false" />
  755. <param name="scale" value="aspect" />
  756. </object>
  757. <!--<![endif]-->
  758. </object></span>
  759. OET;
  760. }