PageRenderTime 63ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/filter/mediaplugin/filter.php

https://github.com/kpike/moodle
PHP | 892 lines | 569 code | 152 blank | 171 comment | 73 complexity | ebb61458629b1f70a93c195ea76293e4 MD5 | raw file
  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 bellow 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. * Parse list of alternative URLs
  135. * @param string $url urls separated with '#', size specified as ?d=640x480 or #d=640x480
  136. * @return array (urls, width, height)
  137. */
  138. function filter_mediaplugin_parse_alternatives($url, $defaultwidth = 0, $defaultheight = 0) {
  139. $urls = explode('#', $url);
  140. $width = $defaultwidth;
  141. $height = $defaultheight;
  142. $returnurls = array();
  143. foreach ($urls as $url) {
  144. $matches = null;
  145. if (preg_match('/^d=([\d]{1,4})x([\d]{1,4})$/i', $url, $matches)) { // #d=640x480
  146. $width = $matches[1];
  147. $height = $matches[2];
  148. continue;
  149. }
  150. if (preg_match('/\?d=([\d]{1,4})x([\d]{1,4})$/i', $url, $matches)) { // old style file.ext?d=640x480
  151. $width = $matches[1];
  152. $height = $matches[2];
  153. $url = str_replace($matches[0], '', $url);
  154. }
  155. $url = str_replace('&amp;', '&', $url);
  156. $url = clean_param($url, PARAM_URL);
  157. if (empty($url)) {
  158. continue;
  159. }
  160. $returnurls[] = $url;
  161. }
  162. return array($returnurls, $width, $height);
  163. }
  164. /**
  165. * Should the current tag be ignored in this filter?
  166. * @param string $tag
  167. * @return bool
  168. */
  169. function filter_mediaplugin_ignore($tag) {
  170. if (preg_match('/class="[^"]*nomediaplugin/i', $tag)) {
  171. return true;
  172. } else {
  173. false;
  174. }
  175. }
  176. ///===========================
  177. /// callback filter functions
  178. /**
  179. * Replace audio links with audio tag.
  180. *
  181. * @param array $link
  182. * @return string
  183. */
  184. function filter_mediaplugin_html5audio_callback(array $link) {
  185. global $CFG;
  186. if (filter_mediaplugin_ignore($link[0])) {
  187. return $link[0];
  188. }
  189. $info = trim($link[4]);
  190. if (empty($info) or strpos($info, 'http') === 0) {
  191. $info = get_string('fallbackaudio', 'filter_mediaplugin');
  192. }
  193. list($urls, $ignorewidth, $ignoredheight) = filter_mediaplugin_parse_alternatives($link[1]);
  194. $fallbackurl = null;
  195. $fallbackmime = null;
  196. $sources = array();
  197. $fallbacklink = null;
  198. foreach ($urls as $url) {
  199. $mimetype = mimeinfo('type', $url);
  200. if (strpos($mimetype, 'audio/') !== 0) {
  201. continue;
  202. }
  203. $sources[] = html_writer::tag('source', '', array('src' => $url, 'type' => $mimetype));
  204. if ($fallbacklink === null) {
  205. $fallbacklink = html_writer::link($url.'#', $info); // the extra '#' prevents linking in mp3 filter bellow
  206. }
  207. if ($fallbackurl === null) {
  208. if ($mimetype === 'audio/mp3' or $mimetype === 'audio/aac') {
  209. $fallbackurl = str_replace('&', '&amp;', $url);
  210. $fallbackmime = $mimetype;
  211. }
  212. }
  213. }
  214. if (!$sources) {
  215. return $link[0];
  216. }
  217. if ($fallbackmime !== null) {
  218. // fallback to quicktime
  219. $fallback = <<<OET
  220. <object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab" width="200" height="20">
  221. <param name="pluginspage" value="http://www.apple.com/quicktime/download/" />
  222. <param name="src" value="$fallbackurl" />
  223. <param name="controller" value="true" />
  224. <param name="loop" value="false" />
  225. <param name="autoplay" value="false" />
  226. <param name="autostart" value="false" />
  227. <param name="scale" value="aspect" />
  228. $fallbacklink
  229. <!--[if !IE]>-->
  230. <object data="$fallbackurl" type="$fallbackmime" width="200" height="20">
  231. <param name="src" value="$fallbackurl" />
  232. <param name="pluginurl" value="http://www.apple.com/quicktime/download/" />
  233. <param name="controller" value="true" />
  234. <param name="loop" value="false" />
  235. <param name="autoplay" value="false" />
  236. <param name="autostart" value="false" />
  237. <param name="scale" value="aspect" />
  238. $fallbacklink
  239. </object>
  240. <!--<![endif]-->
  241. </object>
  242. OET;
  243. } else {
  244. $fallback = $fallbacklink;
  245. }
  246. $sources = implode("\n", $sources);
  247. $title = s($info);
  248. // audio players are supposed to be inline elements
  249. $output = <<<OET
  250. <audio controls="true" width="200" class="mediaplugin mediaplugin_html5audio" preload="no" title="$title">
  251. $sources
  252. $fallback
  253. </audio>
  254. OET;
  255. return $output;
  256. }
  257. /**
  258. * Replace ogg video links with video tag.
  259. *
  260. * Please note this is not going to work in all browsers,
  261. * it is also not xhtml strict.
  262. *
  263. * @param array $link
  264. * @return string
  265. */
  266. function filter_mediaplugin_html5video_callback(array $link) {
  267. if (filter_mediaplugin_ignore($link[0])) {
  268. return $link[0];
  269. }
  270. $info = trim($link[4]);
  271. if (empty($info) or strpos($info, 'http') === 0) {
  272. $info = get_string('fallbackvideo', 'filter_mediaplugin');
  273. }
  274. list($urls, $width, $height) = filter_mediaplugin_parse_alternatives($link[1], FILTER_MEDIAPLUGIN_VIDEO_WIDTH, 0);
  275. $fallbackurl = null;
  276. $fallbackmime = null;
  277. $sources = array();
  278. $fallbacklink = null;
  279. foreach ($urls as $url) {
  280. $mimetype = mimeinfo('type', $url);
  281. if (strpos($mimetype, 'video/') !== 0) {
  282. continue;
  283. }
  284. $source = html_writer::tag('source', '', array('src' => $url, 'type' => $mimetype));
  285. if ($mimetype === 'video/mp4') {
  286. // better add m4v as first source, it might be a bit more compatible with problematic browsers
  287. array_unshift($sources, $source);
  288. } else {
  289. $sources[] = $source;
  290. }
  291. if ($fallbacklink === null) {
  292. $fallbacklink = html_writer::link($url.'#', $info); // the extra '#' prevents linking in mp3 filter bellow
  293. }
  294. if ($fallbackurl === null) {
  295. if ($mimetype === 'video/mp4') {
  296. $fallbackurl = str_replace('&', '&amp;', $url);
  297. $fallbackmime = $mimetype;
  298. }
  299. }
  300. }
  301. if (!$sources) {
  302. return $link[0];
  303. }
  304. if ($fallbackmime !== null) {
  305. $qtheight = ($height == 0) ? FILTER_MEDIAPLUGIN_VIDEO_HEIGHT : ($height + 15);
  306. // fallback to quicktime
  307. $fallback = <<<OET
  308. <object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab" width="$width" height="$qtheight">
  309. <param name="pluginspage" value="http://www.apple.com/quicktime/download/" />
  310. <param name="src" value="$fallbackurl" />
  311. <param name="controller" value="true" />
  312. <param name="loop" value="false" />
  313. <param name="autoplay" value="false" />
  314. <param name="autostart" value="false" />
  315. <param name="scale" value="aspect" />
  316. $fallbacklink
  317. <!--[if !IE]>-->
  318. <object data="$fallbackurl" type="$fallbackmime" width="$width" height="$qtheight">
  319. <param name="src" value="$fallbackurl" />
  320. <param name="pluginurl" value="http://www.apple.com/quicktime/download/" />
  321. <param name="controller" value="true" />
  322. <param name="loop" value="false" />
  323. <param name="autoplay" value="false" />
  324. <param name="autostart" value="false" />
  325. <param name="scale" value="aspect" />
  326. $fallbacklink
  327. </object>
  328. <!--<![endif]-->
  329. </object>
  330. OET;
  331. } else {
  332. $fallback = $fallbacklink;
  333. }
  334. $sources = implode("\n", $sources);
  335. $title = s($info);
  336. if (empty($height)) {
  337. // automatic height
  338. $size = "width=\"$width\"";
  339. } else {
  340. $size = "width=\"$width\" height=\"$height\"";
  341. }
  342. $output = <<<OET
  343. <span class="mediaplugin mediaplugin_html5video">
  344. <video controls="true" $size preload="metadata" title="$title">
  345. $sources
  346. $fallback
  347. </video>
  348. </span>
  349. OET;
  350. return $output;
  351. }
  352. /**
  353. * Replace mp3 links with small audio player.
  354. *
  355. * @param $link
  356. * @return string
  357. */
  358. function filter_mediaplugin_mp3_callback($link) {
  359. static $count = 0;
  360. if (filter_mediaplugin_ignore($link[0])) {
  361. return $link[0];
  362. }
  363. $count++;
  364. $id = 'filter_mp3_'.time().'_'.$count; //we need something unique because it might be stored in text cache
  365. $url = $link[1];
  366. $rawurl = str_replace('&amp;', '&', $url);
  367. $info = trim($link[2]);
  368. if (empty($info) or strpos($info, 'http') === 0) {
  369. $info = get_string('mp3audio', 'filter_mediaplugin');
  370. }
  371. $printlink = html_writer::link($rawurl, $info, array('class'=>'mediafallbacklink'));
  372. //note: when flash or javascript not available only the $printlink is displayed,
  373. // audio players are supposed to be inline elements
  374. $output = html_writer::tag('span', $printlink, array('id'=>$id, 'class'=>'mediaplugin mediaplugin_mp3'));
  375. $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
  376. return $output;
  377. }
  378. /**
  379. * Replace swf links with embedded flash objects.
  380. *
  381. * Please note this is not a secure and is recommended to be disabled on production systems.
  382. *
  383. * @deprecated
  384. * @param $link
  385. * @return string
  386. */
  387. function filter_mediaplugin_swf_callback($link) {
  388. if (filter_mediaplugin_ignore($link[0])) {
  389. return $link[0];
  390. }
  391. $width = empty($link[3]) ? FILTER_MEDIAPLUGIN_VIDEO_WIDTH : $link[3];
  392. $height = empty($link[4]) ? FILTER_MEDIAPLUGIN_VIDEO_HEIGHT : $link[4];
  393. $url = $link[1];
  394. $rawurl = str_replace('&amp;', '&', $url);
  395. $info = trim($link[5]);
  396. if (empty($info) or strpos($info, 'http') === 0) {
  397. $info = get_string('flashanimation', 'filter_mediaplugin');
  398. }
  399. $printlink = html_writer::link($rawurl, $info, array('class'=>'mediafallbacklink'));
  400. $output = <<<OET
  401. <span class="mediaplugin mediaplugin_swf">
  402. <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="$width" height="$height">
  403. <param name="movie" value="$url" />
  404. <param name="autoplay" value="true" />
  405. <param name="loop" value="true" />
  406. <param name="controller" value="true" />
  407. <param name="scale" value="aspect" />
  408. <param name="base" value="." />
  409. <param name="allowscriptaccess" value="never" />
  410. <!--[if !IE]>-->
  411. <object type="application/x-shockwave-flash" data="$url" width="$width" height="$height">
  412. <param name="controller" value="true" />
  413. <param name="autoplay" value="true" />
  414. <param name="loop" value="true" />
  415. <param name="scale" value="aspect" />
  416. <param name="base" value="." />
  417. <param name="allowscriptaccess" value="never" />
  418. <!--<![endif]-->
  419. $printlink
  420. <!--[if !IE]>-->
  421. </object>
  422. <!--<![endif]-->
  423. </object>
  424. </span>
  425. OET;
  426. return $output;
  427. }
  428. /**
  429. * Replace flv links with flow player.
  430. *
  431. * @param $link
  432. * @return string
  433. */
  434. function filter_mediaplugin_flv_callback($link) {
  435. static $count = 0;
  436. if (filter_mediaplugin_ignore($link[0])) {
  437. return $link[0];
  438. }
  439. $count++;
  440. $id = 'filter_flv_'.time().'_'.$count; //we need something unique because it might be stored in text cache
  441. list($urls, $width, $height) = filter_mediaplugin_parse_alternatives($link[1], 0, 0);
  442. $autosize = false;
  443. if (!$width and !$height) {
  444. $width = FILTER_MEDIAPLUGIN_VIDEO_WIDTH;
  445. $height = FILTER_MEDIAPLUGIN_VIDEO_HEIGHT;
  446. $autosize = true;
  447. }
  448. $flashurl = null;
  449. $sources = array();
  450. foreach ($urls as $url) {
  451. $mimetype = mimeinfo('type', $url);
  452. if (strpos($mimetype, 'video/') !== 0) {
  453. continue;
  454. }
  455. $source = html_writer::tag('source', '', array('src' => $url, 'type' => $mimetype));
  456. if ($mimetype === 'video/mp4') {
  457. // better add m4v as first source, it might be a bit more compatible with problematic browsers
  458. array_unshift($sources, $source);
  459. } else {
  460. $sources[] = $source;
  461. }
  462. if ($flashurl === null) {
  463. $flashurl = str_replace('&', '&amp;', $url);
  464. }
  465. }
  466. if (!$sources) {
  467. return $link[0];
  468. }
  469. $info = trim($link[4]);
  470. if (empty($info) or strpos($info, 'http') === 0) {
  471. $info = get_string('fallbackvideo', 'filter_mediaplugin');
  472. }
  473. $printlink = html_writer::link($flashurl.'#', $info, array('class'=>'mediafallbacklink')); // the '#' prevents the QT filter
  474. $title = s($info);
  475. if (count($sources) > 1) {
  476. $sources = implode("\n", $sources);
  477. // html 5 fallback
  478. $printlink = <<<OET
  479. <video controls="true" width="$width" height="$height" preload="metadata" title="$title">
  480. $sources
  481. $printlink
  482. </video>
  483. <noscript><br />
  484. $printlink
  485. </noscript>
  486. OET;
  487. }
  488. // note: no need to print "this is flv link" because it is printed automatically if JS or Flash not available
  489. $output = html_writer::tag('span', $printlink, array('id'=>$id, 'class'=>'mediaplugin mediaplugin_flv'));
  490. $output .= html_writer::script(js_writer::function_call('M.util.add_video_player', array($id, $flashurl, $width, $height, $autosize))); // we can not use standard JS init because this may be cached
  491. return $output;
  492. }
  493. /**
  494. * Replace real media links with real player.
  495. *
  496. * Note: hopefully nobody is using this obsolete format any more.
  497. *
  498. * @deprectated
  499. * @param $link
  500. * @return string
  501. */
  502. function filter_mediaplugin_real_callback($link) {
  503. if (filter_mediaplugin_ignore($link[0])) {
  504. return $link[0];
  505. }
  506. $url = $link[1];
  507. $rawurl = str_replace('&amp;', '&', $url);
  508. //Note: the size is hardcoded intentionally because this does not work anyway!
  509. $width = FILTER_MEDIAPLUGIN_VIDEO_WIDTH;
  510. $height = FILTER_MEDIAPLUGIN_VIDEO_HEIGHT;
  511. $info = trim($link[3]);
  512. if (empty($info) or strpos($info, 'http') === 0) {
  513. $info = get_string('fallbackvideo', 'filter_mediaplugin');
  514. }
  515. $printlink = html_writer::link($rawurl, $info, array('class'=>'mediafallbacklink'));
  516. return <<<OET
  517. <span class="mediaplugin mediaplugin_real">
  518. $printlink <br />
  519. <object title="$info" classid="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" data="$url" width="$width" height="$height"">
  520. <param name="src" value="$url" />
  521. <param name="controls" value="All" />
  522. <!--[if !IE]>-->
  523. <object title="$info" type="audio/x-pn-realaudio-plugin" data="$url" width="$width" height="$height">
  524. <param name="src" value="$url" />
  525. <param name="controls" value="All" />
  526. <!--<![endif]-->
  527. <!--[if !IE]>-->
  528. </object>
  529. <!--<![endif]-->
  530. </object>
  531. </span>
  532. OET;
  533. }
  534. /**
  535. * Change links to YouTube into embedded YouTube videos
  536. *
  537. * Note: resizing via url is not supported, user can click the fullscreen button instead
  538. *
  539. * @param $link
  540. * @return string
  541. */
  542. function filter_mediaplugin_youtube_callback($link) {
  543. global $CFG;
  544. if (filter_mediaplugin_ignore($link[0])) {
  545. return $link[0];
  546. }
  547. $site = $link[1];
  548. $videoid = $link[3];
  549. $info = trim($link[7]);
  550. if (empty($info) or strpos($info, 'http') === 0) {
  551. $info = get_string('siteyoutube', 'filter_mediaplugin');
  552. }
  553. $info = s($info);
  554. $width = empty($link[5]) ? FILTER_MEDIAPLUGIN_VIDEO_WIDTH : $link[5];
  555. $height = empty($link[6]) ? FILTER_MEDIAPLUGIN_VIDEO_HEIGHT : $link[6];
  556. if (empty($CFG->xmlstrictheaders)) {
  557. return <<<OET
  558. <iframe title="$info" width="$width" height="$height" src="$site/embed/$videoid?rel=0" frameborder="0" allowfullscreen></iframe>
  559. OET;
  560. }
  561. //NOTE: we can not use any link fallback because it breaks built-in player on iOS devices
  562. $output = <<<OET
  563. <span class="mediaplugin mediaplugin_youtube">
  564. <object title="$info" type="application/x-shockwave-flash" data="$site/v/$videoid&amp;fs=1&amp;rel=0" width="$width" height="$height">
  565. <param name="movie" value="$site/v/$videoid&amp;fs=1&amp;rel=0" />
  566. <param name="FlashVars" value="playerMode=embedded" />
  567. <param name="allowFullScreen" value="true" />
  568. </object>
  569. </span>
  570. OET;
  571. return $output;
  572. }
  573. /**
  574. * Change YouTube playlist into embedded YouTube playlist videos
  575. *
  576. * Note: resizing via url is not supported, user can click the fullscreen button instead
  577. *
  578. * @param $link
  579. * @return string
  580. */
  581. function filter_mediaplugin_youtube_playlist_callback($link) {
  582. global $CFG;
  583. if (filter_mediaplugin_ignore($link[0])) {
  584. return $link[0];
  585. }
  586. $site = $link[1];
  587. $playlist = $link[3];
  588. $info = trim($link[7]);
  589. if (empty($info) or strpos($info, 'http') === 0) {
  590. $info = get_string('siteyoutube', 'filter_mediaplugin');
  591. }
  592. $printlink = html_writer::link("$site/view_play_list\?p=$playlist", $info, array('class'=>'mediafallbacklink'));
  593. $info = s($info);
  594. $width = empty($link[5]) ? FILTER_MEDIAPLUGIN_VIDEO_WIDTH : $link[5];
  595. $height = empty($link[6]) ? FILTER_MEDIAPLUGIN_VIDEO_HEIGHT : $link[6];
  596. // TODO: iframe HTML 5 video not implemented and object does work on iOS devices
  597. $output = <<<OET
  598. <span class="mediaplugin mediaplugin_youtube">
  599. <object title="$info" type="application/x-shockwave-flash" data="$site/p/$playlist&amp;fs=1&amp;rel=0" width="$width" height="$height">
  600. <param name="movie" value="$site/v/$playlist&amp;fs=1&amp;rel=0" />
  601. <param name="FlashVars" value="playerMode=embedded" />
  602. <param name="allowFullScreen" value="true" />
  603. $printlink</object>
  604. </span>
  605. OET;
  606. return $output;
  607. }
  608. /**
  609. * Change links to Vimeo into embedded Vimeo videos
  610. *
  611. * @param $link
  612. * @return string
  613. */
  614. function filter_mediaplugin_vimeo_callback($link) {
  615. global $CFG;
  616. if (filter_mediaplugin_ignore($link[0])) {
  617. return $link[0];
  618. }
  619. $videoid = $link[1];
  620. $info = s(strip_tags($link[5]));
  621. //Note: resizing via url is not supported, user can click the fullscreen button instead
  622. // iframe embedding is not xhtml strict but it is the only option that seems to work on most devices
  623. $width = empty($link[3]) ? FILTER_MEDIAPLUGIN_VIDEO_WIDTH : $link[3];
  624. $height = empty($link[4]) ? FILTER_MEDIAPLUGIN_VIDEO_HEIGHT : $link[4];
  625. $output = <<<OET
  626. <span class="mediaplugin mediaplugin_vimeo">
  627. <iframe title="$info" src="http://player.vimeo.com/video/$videoid" width="$width" height="$height" frameborder="0"></iframe>
  628. </span>
  629. OET;
  630. return $output;
  631. }
  632. /**
  633. * Embed video using window media player if available
  634. *
  635. * This does not work much outside of IE, hopefully not many ppl use it these days.
  636. *
  637. * @param $link
  638. * @return string
  639. */
  640. function filter_mediaplugin_wmp_callback($link) {
  641. if (filter_mediaplugin_ignore($link[0])) {
  642. return $link[0];
  643. }
  644. $url = $link[1];
  645. $rawurl = str_replace('&amp;', '&', $url);
  646. $info = trim($link[6]);
  647. if (empty($info) or strpos($info, 'http') === 0) {
  648. $info = get_string('fallbackvideo', 'filter_mediaplugin');
  649. }
  650. $printlink = html_writer::link($rawurl, $info, array('class'=>'mediafallbacklink'));
  651. if (empty($link[4]) or empty($link[5])) {
  652. $mpsize = '';
  653. $size = 'width="'.FILTER_MEDIAPLUGIN_VIDEO_WIDTH.'" height="'.(FILTER_MEDIAPLUGIN_VIDEO_HEIGHT+64).'"';
  654. $autosize = 'true';
  655. } else {
  656. $size = 'width="'.$link[4].'" height="'.($link[5] + 15).'"';
  657. $mpsize = 'width="'.$link[4].'" height="'.($link[5] + 64).'"';
  658. $autosize = 'false';
  659. }
  660. $mimetype = mimeinfo('type', $url);
  661. return <<<OET
  662. <span class="mediaplugin mediaplugin_wmp">
  663. $printlink <br />
  664. <object classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6" $mpsize standby="Loading Microsoft(R) Windows(R) Media Player components..." type="application/x-oleobject">
  665. <param name="Filename" value="$url" />
  666. <param name="src" value="$url" />
  667. <param name="url" value="$url" />
  668. <param name="ShowControls" value="true" />
  669. <param name="AutoRewind" value="true" />
  670. <param name="AutoStart" value="false" />
  671. <param name="Autosize" value="$autosize" />
  672. <param name="EnableContextMenu" value="true" />
  673. <param name="TransparentAtStart" value="false" />
  674. <param name="AnimationAtStart" value="false" />
  675. <param name="ShowGotoBar" value="false" />
  676. <param name="EnableFullScreenControls" value="true" />
  677. <param name="uimode" value="full" />
  678. <!--[if !IE]>-->
  679. <object data="$url" type="$mimetype" $size>
  680. <param name="src" value="$url" />
  681. <param name="controller" value="true" />
  682. <param name="autoplay" value="false" />
  683. <param name="autostart" value="false" />
  684. <param name="resize" value="scale" />
  685. </object>
  686. <!--<![endif]-->
  687. </object></span>
  688. OET;
  689. }
  690. /**
  691. * Replace quicktime links with quicktime player.
  692. *
  693. * You need to install a quicktime player, it is not available for all browsers+OS combinations.
  694. *
  695. * @param $link
  696. * @return string
  697. */
  698. function filter_mediaplugin_qt_callback($link) {
  699. if (filter_mediaplugin_ignore($link[0])) {
  700. return $link[0];
  701. }
  702. $url = $link[1];
  703. $rawurl = str_replace('&amp;', '&', $url);
  704. $info = trim($link[6]);
  705. if (empty($info) or strpos($info, 'http') === 0) {
  706. $info = get_string('fallbackvideo', 'filter_mediaplugin');
  707. }
  708. $printlink = html_writer::link($rawurl, $info, array('class'=>'mediafallbacklink'));
  709. if (empty($link[4]) or empty($link[5])) {
  710. $size = 'width="'.FILTER_MEDIAPLUGIN_VIDEO_WIDTH.'" height="'.(FILTER_MEDIAPLUGIN_VIDEO_HEIGHT+15).'"';
  711. } else {
  712. $size = 'width="'.$link[4].'" height="'.($link[5]+15).'"';
  713. }
  714. $mimetype = mimeinfo('type', $url);
  715. // this is the safest fallback for incomplete or missing browser support for this format
  716. return <<<OET
  717. <span class="mediaplugin mediaplugin_qt">
  718. $printlink <br />
  719. <object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab" $size>
  720. <param name="pluginspage" value="http://www.apple.com/quicktime/download/" />
  721. <param name="src" value="$url" />
  722. <param name="controller" value="true" />
  723. <param name="loop" value="true" />
  724. <param name="autoplay" value="false" />
  725. <param name="autostart" value="false" />
  726. <param name="scale" value="aspect" />
  727. <!--[if !IE]>-->
  728. <object data="$url" type="$mimetype" $size>
  729. <param name="src" value="$url" />
  730. <param name="pluginurl" value="http://www.apple.com/quicktime/download/" />
  731. <param name="controller" value="true" />
  732. <param name="loop" value="true" />
  733. <param name="autoplay" value="false" />
  734. <param name="autostart" value="false" />
  735. <param name="scale" value="aspect" />
  736. </object>
  737. <!--<![endif]-->
  738. </object></span>
  739. OET;
  740. }