/mediafilter/class.php
PHP | 892 lines | 653 code | 71 blank | 168 comment | 57 complexity | b73b08c64fa9fc2b64f44009768b0e45 MD5 | raw file
- <?php
- // This file is part of Moodle - http://moodle.org/
- //
- // Moodle is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // Moodle is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
- /**
- * mod/hotpot/mediafilter/class.php
- *
- * @package mod-hotpot
- * @copyright 2010 Gordon Bateson <gordon.bateson@gmail.com>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
- defined('MOODLE_INTERNAL') || die();
- // get the standard Moodle mediaplugin filter
- require_once($CFG->dirroot.'/filter/mediaplugin/filter.php');
- /**
- * hotpot_mediafilter
- *
- * @copyright 2010 Gordon Bateson
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @since Moodle 2.0
- */
- class hotpot_mediafilter {
- // media filetypes that this filter can handle
- // this initial list is of the file types that Moodle's standard mediaplugin can handle
- // media file types specified by individual media players will be added to this list
- public $media_filetypes = array(
- // any params allowed (flash audio/video, html5 audio/video)
- 'aac'=>'any', 'f4v'=>'any', 'flv'=>'any', 'm4a'=>'any', 'm4v'=>'any',
- 'mp4'=>'any', 'oga'=>'any', 'ogg'=>'any', 'ogv'=>'any', 'webm'=>'any',
- // only "d=WIDTHxHEIGHT" param allowed in moodle filter
- 'avi'=>'size', 'm4v'=>'size', 'm4a'=>'size', 'mov'=>'size',
- 'mp4'=>'size', 'mpeg'=>'size', 'mpg'=>'size', 'swf'=>'size', 'wmv'=>'size',
- // no params allowed in moodle filter
- 'mp3'=>'none', 'ra'=>'none', 'ram'=>'none', 'rm'=>'none', 'rv'=>'none'
- );
- public $param_names = 'movie|src|url';
- // wmp : url
- // quicktime : src
- // realplayer : src
- // flash : movie
- public $tagopen = '(?:(<)|(\\\\u003C))'; // left angle-bracket (uses two parenthese)
- public $tagchars = '(?(1)[^>]|(?(2).(?!\\\\u003E)))*?'; // string of chars inside the tag
- public $tagclose = '(?(1)>|(?(2)\\\\u003E))'; // right angle-bracket (to match the left one)
- public $tagreopen = '(?(1)<|(?(2)\\\\u003C))'; // another left angle-bracket (to match the first one)
- //$tagopen = '(?:(<)|(<)|(&#x003C;))';
- //$tagclose = '(?(2)>|(?(3)>|(?(4)&#x003E;)))';
- public $link_search = '';
- public $object_search = '';
- public $object_searches = array();
- public $js_inline = '';
- public $js_external = '';
- public $players = array();
- public $defaultplayer = 'moodle';
- public $moodle_flashvars = array('waitForPlay', 'autoPlay', 'buffer');
- // bgColour, btnColour, btnBorderColour,
- // iconColour, iconOverColour,
- // trackColour, handleColour, loaderColour,
- // waitForPlay, autoPlay, buffer
- // constructor function
- /**
- * __construct
- *
- * @param xxx $output (passed by reference)
- */
- function __construct($output) {
- global $CFG, $THEME;
- $this->players[$this->defaultplayer] = new hotpot_mediaplayer();
- $flashvars_paramnames = array();
- $querystring_paramname = array();
- $players = get_list_of_plugins('mod/hotpot/mediafilter/hotpot'); // sorted
- foreach ($players as $player) {
- $filepath = $CFG->dirroot.'/mod/hotpot/mediafilter/hotpot/'.$player.'/class.php';
- if (file_exists($filepath) && include_once($filepath)) {
- $playerclass = 'hotpot_mediaplayer_'.$player;
- $this->players[$player] = new $playerclass();
- // note the names urls in flashvars and querystring
- if ($name = $this->players[$player]->flashvars_paramname) {
- $flashvars_paramnames[$name] = true;
- }
- if ($name = $this->players[$player]->querystring_paramname) {
- $querystring_paramnames[$name] = true;
- }
- // add aliases to this player
- foreach ($this->players[$player]->aliases as $alias) {
- $this->players[$alias] =&$this->players[$player];
- }
- // add any new media file types
- foreach ($this->players[$player]->media_filetypes as $filetype) {
- if (! array_key_exists($filetype, $this->media_filetypes)) {
- $this->media_filetypes[$filetype] = '';
- }
- }
- }
- }
- $filetypes = implode('|', array_keys($this->media_filetypes));
- $filepath = '[^"'."'?]*".'\.('.$filetypes.')[^"'."']*";
- // detect backslash before double quotes and slashes within JavaScript
- $escape = '(?:\\\\)?';
- // search string to extract <a> tags
- $this->link_search = '/'.$this->tagopen.'a'.'\s+'.$this->tagchars.'href='.$escape.'"('.$filepath.')'.$escape.'"'.$this->tagchars.$this->tagclose.'.*?'.$this->tagreopen.$escape.'\/a'.$this->tagclose.'/is';
- // search string to extract <object> or <embed> tags
- $this->object_search = '/'.$this->tagopen.'(object|embed)'.'\s'.$this->tagchars.$this->tagclose.'(.*?)(?:'.$this->tagreopen.'(?:\\\\)?'.'\/\3'.$this->tagclose.')+/is';
- // search Flashvars with specific names
- // $flashvars_paramnames e.g. TheSound
- // e.g. param name="Flashvars" value="TheSound=abc.mp3"
- if ($flashvars_paramnames = implode('|', array_keys($flashvars_paramnames))) {
- $this->object_searches[] = '/'.$this->tagopen.'param'.'\s+'.$this->tagchars.'name='.$escape.'"FlashVars'.$escape.'"'.$this->tagchars.'value='.$escape.'"(?:'.$flashvars_paramnames.')=('.$filepath.')'.$escape.'"'.$this->tagchars.$this->tagclose.'/is';
- }
- // html tags and attributes to search for urls
- $tags = array(
- 'object'=>'data', 'embed'=>'src', 'a'=>'href'
- );
- // search for specific querystrings
- // e.g. param name="movie" value="player.swf?mp3=abc.mp3"
- // e.g. object data="player.swf?mp3=abc.mp3"
- // e.g. embed src="player.swf?mp3=abc.mp3"
- // e.g. a href="player.swf?mp3=abc.mp3"
- if ($querystring_paramnames = implode('|', array_keys($querystring_paramnames))) {
- $querystring_filepath = '[^"'."'?]*".'\?[^"'."']*(?:$querystring_paramnames)=($filepath)".'[^"'."']*";
- if ($this->param_names) {
- $this->object_searches[] = '/'.$this->tagopen.'param'.'\s+'.$this->tagchars.'name='.$escape.'"(?:'.$this->param_names.')'.$escape.'"'.$this->tagchars.'value='.$escape.'"'.$querystring_filepath.$escape.'"'.$this->tagchars.$this->tagclose.'/is';
- }
- foreach ($tags as $tag => $attribute) {
- $this->object_searches[] = '/'.$this->tagopen.$tag.'\s+'.$this->tagchars.$attribute.'='.$escape.'"'.$querystring_filepath.$escape.'"'.$this->tagchars.$this->tagclose.'.*?'.$this->tagreopen.$escape.'\/'.$tag.$this->tagclose.'/is';
- }
- }
- // search for full urls
- // e.g. param name="movie" value="abc.mp3"
- // e.g. object data="mp3=abc.mp3"
- // e.g. embed src="abc=abc.mp3"
- // e.g. a href="abc=abc.mp3"
- if ($this->param_names) {
- $this->object_searches[] = '/'.$this->tagopen.'param'.'\s+'.$this->tagchars.'name='.$escape.'"(?:'.$this->param_names.')'.$escape.'"'.$this->tagchars.'value='.$escape.'"('.$filepath.')'.$escape.'"'.$this->tagchars.$this->tagclose.'/is';
- }
- foreach ($tags as $tag => $attribute) {
- $this->object_searches[] = '/'.$this->tagopen.$tag.'\s+'.$this->tagchars.$attribute.'='.$escape.'"('.$filepath.')'.$escape.'"'.$this->tagchars.$this->tagclose.'.*?'.$this->tagreopen.$escape.'\/'.$tag.$this->tagclose.'/is';
- }
- // check player settings
- $names = array_keys($this->players);
- foreach ($names as $name) {
- // convert player url to absolute url
- $player = &$this->players[$name];
- if ($player->playerurl && ! preg_match('/^(?:https?:)?\/+/i', $player->playerurl)) {
- $player->playerurl = $CFG->wwwroot.'/mod/hotpot/mediafilter/hotpot/'.$player->playerurl;
- }
- // set basic flashvars settings
- $options = &$player->options;
- if (is_null($options['flashvars'])) {
- if (empty($THEME->filter_mediaplugin_colors)) {
- $options['flashvars'] = ''
- .'bgColour=000000&'
- .'btnColour=ffffff&'.'btnBorderColour=cccccc&'
- .'iconColour=000000&'.'iconOverColour=00cc00&'
- .'trackColour=cccccc&'.'handleColour=ffffff&'
- .'loaderColour=ffffff&'.'waitForPlay=yes'
- ;
- } else {
- // You can set this up in your theme/xxx/config.php
- $options['flashvars'] = $THEME->filter_mediaplugin_colors;
- }
- $options['flashvars'] = htmlspecialchars($options['flashvars']);
- }
- }
- }
- /**
- * fix
- *
- * @param xxx $text
- * @param xxx $output (passed by reference)
- */
- function fix($text, $output) {
- $this->fix_objects($text, $output);
- $this->fix_links($text, $output);
- $this->fix_specials($text, $output);
- }
- /**
- * fix_objects
- *
- * @param xxx $text
- * @param xxx $output (passed by reference)
- */
- function fix_objects($text, $output) {
- // Segments[0][0] = '<object classid=\"CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6\" width=\"100\" height=\"30\"><param name=\"url\" value=\"http://localhost/moodle/19/mysql/file.php/2/hennyjellema/frag.01.mp3\" /><param name=\"autostart\" value=\"false\" /><param name=\"showcontrols\" value=\"true\" /><\/object>';
- $callback = array($this, 'fix_object');
- $callback = partial($callback, $output);
- $output->$text = preg_replace_callback($this->object_search, $callback, $output->$text);
- }
- /**
- * fix_object
- *
- * @param xxx $output (passed by reference)
- * @param xxx $object
- * @param xxx $unicode
- * @param xxx $quote (optional, default="'")
- * @return xxx
- */
- function fix_object($output, $match) {
- $object = $match[0];
- $unicode = $match[2];
- $url = '';
- $filetype = '';
- foreach ($this->object_searches as $search) {
- if (preg_match($search, $object, $matches)) {
- $url = $matches[3];
- $filetype = $matches[4];
- break;
- }
- }
- if ($url=='') {
- return $object;
- }
- // strip inner tags (e.g. <embed>)
- $txt = preg_replace('/'.$this->tagopen.'.*?'.$this->tagclose.'/', '', $object);
- $txt = trim($txt);
- // if url has a query string, we assume the target url
- // is one of the values in the query string
- // $pos : 0=first value, 1=named value, 2=last value
- $pos = 1;
- switch ($pos) {
- case 0: $search = '/^[^?]*\?'.'[^=]+=([^&]*)'.'.*$/'; break;
- case 1: $search = '/^[^?]*\?'.'(?:file|src|thesound|mp3)+=([^&]*)'.'.*$/'; break;
- case 2: $search = '/^[^?]*\?'.'(?:[^=]+=[^&]*&(?:amp;))*'.'[^=]+=([^&]*)'.'$/'; break;
- }
- $url = preg_replace($search, '$1', $url, 1);
- // create new media player for this media file
- $player = $this->get_defaultplayer($url, $filetype);
- if ($player=='moodle' && isset($this->media_filetypes[$filetype])) {
- $allow = $this->media_filetypes[$filetype];
- $count = 0;
- if ($allow=='size') {
- $url = preg_replace('/^([^?#&]*).*?(d=\d{1,4}x\d{1,4}).*$/', '$1?$2', $url, -1, $count);
- }
- if ($allow=='none' || ($allow=='size' && $count==0)) {
- $url = preg_replace('/^([^?]*)[?#&].*$/', '$1', $url);
- }
- }
- $options = array('unicode' => $unicode, 'player' => $player);
- $link = '<a href="'.$url.'">'.$txt.'</a>';
- return $this->fix_link($output, $options, $link);
- }
- /**
- * fix_specials
- *
- * @param xxx $output (passed by reference)
- * @param xxx $text
- */
- function fix_specials($text, $output) {
- // search for [url player width height options]
- // url : the (relative or absolute) url of the media file
- // player : string of alpha chars (underscore and hyphen are also allowed)
- // "img" or "image" : insert an <img> tag for this url
- // "a" or "link" : insert a link to the url
- // "object" or "movie" : url is a stand-alone movie; insert <object> tags
- // "moodle" : insert a standard moodle media player to play the media file
- // otherwise the url is for a media file, so insert a player to play/display it
- // width : the required display width (e.g. 50 or 50px or 10em)
- // height : the required display height (e.g. 25 or 25px or 5em)
- // options : xx OR xx= OR xx=abc123 OR xx="a b c 1 2 3"
- // Note: only url is required; others values are optional
- $filetypes = implode('|', array_keys($this->media_filetypes));
- $search = ''
- .'/\[\s*'
- .'('.'[^ \]]*?'.'\.(?:'.$filetypes.')(?:\?[^ \]]*)?)' // 1: url (+ querystring)
- .'(\s+[a-z][0-9a-z._-]*)?' // 2: player
- .'(\s+\d+(?:\.\d+)?[a-z]*)?' // 3: width
- .'(\s+\d+(?:\.\d+)?[a-z]*)?' // 4: height
- .'((?:\s+[^ =\]]+(?:=(?:(?:\\\\?"[^"]*")|\w*))?)*)' // 5: options
- .'\s*\]'
- .'((?:\s*<br\s*\/?>)*)' // 6: trailing newlines
- .'/is'
- ;
- $callback = array($this, 'fix_special');
- $callback = partial($callback, $output);
- $output->$text = preg_replace_callback($search, $callback, $output->$text);
- }
- /**
- * fix_special
- *
- * @param xxx $match
- * @param xxx $output (passed by reference)
- * @return xxx
- */
- function fix_special($output, $match) {
- $url = trim($match[1]);
- $player = trim($match[2]);
- $width = trim($match[3]);
- $height = trim($match[4]);
- $options = trim($match[5]);
- $space = trim($match[6]);
- // convert $url to $absoluteurl
- $absoluteurl = $output->convert_url_relative($url);
- //$absoluteurl = $output->convert_url($url, '');
- // set height equal to width, if necessary
- if ($width && ! $height) {
- $height = $width;
- }
- //if ($player=='' && $this->image_filetypes && preg_match('/\.(?:'.$this->image_filetypes.')/i', $url)) {
- // $player = 'img';
- //}
- //if ($player=='img' || $player=='image') {
- // return '<img src="'.$absoluteurl.'" width="'.$width.'" height="'.$height.'" />';
- //}
- if ($player=='') {
- $player = $this->get_defaultplayer($url);
- }
- // $options_array will be passed to mediaplugin_filter
- $options_array = array();
- // add $player, $width and $height to $option_array
- if ($player=='movie' || $player=='object') {
- $options_array['movie'] = $absoluteurl;
- $options_array['skipmediaurl'] = true;
- } else if ($player=='center' || $player=='hide') {
- $options_array[$player] = true;
- $player = '';
- } else if ($player) {
- $options_array['player'] = $player;
- }
- if ($width) {
- $options_array['width'] = $width;
- }
- if ($height) {
- $options_array['height'] = $height;
- }
- // transfer $options to $option_array
- if (preg_match_all('/([^ =\]]+)(=((?:\\\\?"[^"]*")|\w*))?/s', $options, $matches)) {
- $i_max = count($matches[0]);
- for ($i=0; $i<$i_max; $i++) {
- $name = $matches[1][$i];
- if ($matches[2][$i]) {
- $options_array[$name] = trim($matches[3][$i], '"\\');
- } else {
- $options_array[$name] = true; // boolean switch
- }
- }
- }
- // remove trailing space if player is to be centered or hidden
- if (! empty($options_array['center']) || ! empty($options_array['hide'])) {
- $space = '';
- }
- $link = '<a href="'.$absoluteurl.'" target="_blank">'.$url.'</a>';
- return $this->fix_link($output, $options_array, $link).$space;
- }
- /**
- * fix_links
- *
- * @param xxx $output (passed by reference)
- * @param xxx $text
- */
- function fix_links($text, $output) {
- $callback = array($this, 'fix_link');
- $callback = partial($callback, $output, array());
- $output->$text = preg_replace_callback($this->link_search, $callback, $output->$text);
- }
- /**
- * fix_link
- *
- * @param xxx $match
- * @param xxx $output (passed by reference)
- * @param xxx $options (optional, default=array)
- * @return xxx
- */
- function fix_link($output, $options, $match) {
- global $CFG, $PAGE;
- static $load_flowplayer = 0;
- static $eolas_fix_applied = 0;
- if (is_string($match)) {
- $link = $match;
- $unicode = '';
- } else if (is_array($match)) {
- $link = $match[0];
- $unicode = $match[2];
- } else {
- debugging('Oops, $match is not an array or string !');
- $args = func_get_args();
- print_object(count($args));
- die;
- }
- if (array_key_exists('unicode', $options)) {
- $unicode = $options['unicode'];
- }
- // set player default, if necessary
- if (empty($options['player'])) {
- $options['player'] = $this->defaultplayer;
- }
- // hide player if required
- if (array_key_exists('hide', $options)) {
- if ($options['hide']) {
- $options['width'] = 1;
- $options['height'] = 1;
- if ($options['player']=='moodle') {
- $options['autoPlay'] = 'yes';
- $options['waitForPlay'] = 'no';
- }
- }
- unset($options['hide']);
- unset($options['center']);
- }
- // call filter to add media player
- if (empty($options['movie']) && $options['player']=='moodle') {
- $filter = new filter_mediaplugin($output->hotpot->context, array());
- $object = $filter->filter($link);
- if ($object==$link) {
- // do nothing
- } else if ($eolas_fix_applied==$output->hotpot->id) {
- // eolas_fix.js and ufo.js have already been added for this quiz
- } else {
- if ($eolas_fix_applied==0) {
- // 1st quiz - eolas_fix.js was added by filter/mediaplugin/filter.php
- } else {
- // 2nd (or later) quiz - e.g. we are being called by hotpot_cron()
- $PAGE->requires->js('/mod/hotpot/mediafilter/eolas_fix.js');
- //$object .= '<script defer="defer" src="'.$CFG->wwwroot.'/mod/hotpot/mediafilter/eolas_fix.js" type="text/javascript"></script>';
- }
- $PAGE->requires->js('/mod/hotpot/mediafilter/ufo.js', true);
- //$object .= '<script type="text/javascript" src="'.$CFG->wwwroot.'/mod/hotpot/mediafilter/ufo.js"></script>';
- $eolas_fix_applied = $output->hotpot->id;
- }
- $search = '/(flashvars:")([^"]*)(")/';
- $callback = array($this, 'fix_flashvars');
- $callback = partial($callback, $options);
- $object = preg_replace_callback($search, $callback, $object);
- // fix height and width (e.g. height="15", "height": 15)
- foreach (array('width', 'height') as $option) {
- if (array_key_exists($option, $options)) {
- $search = array('/(?<='.$option.':")\w+(?=")/i', '/(?<="'.$option.'": )\w+/i');
- $object = preg_replace($search, $options[$option], $object);
- }
- }
- } else {
- $object = $this->mediaplugin_filter($output->hotpot, $link, $options);
- }
- // center content if required
- if (array_key_exists('center', $options)) {
- if ($options['center']) {
- $object = '<div style="text-align:center;">'.$object.'</div>';
- }
- unset($options['center']);
- }
- // if required, remove the link contained in the object tag
- // Note: strcmp() returns true if strings are different
- $player = $options['player'];
- if ($this->players[$player]->removelink && strcmp($object, $link)) {
- $search = '/<a href="[^"]*"[^>]*>[^<]*<\/a>\s*/is';
- $object = preg_replace($search, '', $object);
- }
- // extract the external javascripts
- $search = '/\s*<script[^>]*src[^>]*>.*?<\/script>\s*/is';
- if (preg_match_all($search, $object, $scripts, PREG_OFFSET_CAPTURE)) {
- foreach (array_reverse($scripts[0]) as $script) {
- // $script: [0] = matched string, [1] = offset to start of string
- // remove the javascript from the player
- $object = substr_replace($object, "\n", $script[1], strlen($script[0]));
- // store this javascript so it can be run later
- $this->js_external = trim($script[0])."\n".$this->js_external;
- }
- }
- // extract the inline javascripts
- $search = '/\s*<script[^>]*>.*?<\/script>\s*/is';
- if (preg_match_all($search, $object, $scripts, PREG_OFFSET_CAPTURE)) {
- foreach (array_reverse($scripts[0]) as $script) {
- // $script: [0] = matched string, [1] = offset to start of string
- // remove the script from the player
- $object = substr_replace($object, "\n", $script[1], strlen($script[0]));
- // format the script (helps readability of the html source)
- $script[0] = $this->format_script($script[0]);
- //store this javascript so it can be run later
- $this->js_inline = trim($script[0])."\n".$this->js_inline;
- }
- if ($this->js_inline && $load_flowplayer==0) {
- $load_flowplayer = 1;
- $this->js_inline .= ''
- .'<script type="text/javascript">'."\n"
- ."//<![CDATA[\n"
- ."\t".'M.util.load_flowplayer();'."\n"
- ."//]]>\n"
- ."</script>\n"
- ;
- }
- }
- // remove white space between tags, standardize other white space to a single space
- $object = preg_replace('/(?<=>)\s+(?=<)/', '', $object);
- $object = preg_replace('/\s+/', ' ', $object);
- if ($unicode) {
- // encode angle brackets as javascript $unicode
- $object = str_replace('<', '\\u003C', $object);
- $object = str_replace('>', '\\u003E', $object);
- //$object = str_replace('&', '&', $object);
- }
- return $object;
- }
- /**
- * get_defaultplayer
- *
- * @param xxx $url
- * @return xxx
- */
- function get_defaultplayer($url, $filetype='') {
- if ($filetype=='') {
- $filetype = pathinfo($url, PATHINFO_EXTENSION);
- }
- foreach ($this->players as $playername => $player) {
- if (in_array($filetype, $player->media_filetypes)) {
- return $playername;
- }
- }
- return $this->defaultplayer;
- }
- /**
- * fix_flashvars
- *
- * @param xxx $match
- * @param xxx $options (passed by reference)
- * @return xxx
- */
- function fix_flashvars($options, $match) {
- global $CFG;
- $before = $match[1];
- $flashvars = $match[2];
- $after = $match[3];
- // entities_to_utf8() is required undo the call to htmlentities(), see MDL-5223
- // this is necessary to allow waitForPlay and autoPlay to be effective on Firefox
- $flashvars = hotpot_textlib('entities_to_utf8', $flashvars);
- $vars = explode('&', $flashvars);
- foreach ($this->moodle_flashvars as $var) {
- if (array_key_exists($var, $options)) {
- $vars = preg_grep("/^$var=/", $vars, PREG_GREP_INVERT);
- $vars[] = "$var=".hotpot_textlib('utf8_to_entities', $options[$var]);
- }
- }
- return $before.implode('&', $vars).$after;
- }
- /**
- * format_script
- *
- * @param xxx $str
- * @param xxx $quote (optional, default="'")
- * @return xxx
- */
- function format_script($str) {
- // fix indents
- $str = preg_replace('/^ +/m', "\t", $str);
- // format FO (Flash Object) properties (one property per line)
- $search = '/var FO\s*=\s*\{\s*(.*?)\s*\}/is';
- // $1 : properties of the FO object
- if (preg_match_all($search, $str, $matches, PREG_OFFSET_CAPTURE)) {
- $search = '/\s*(\w+)\s*:\s*(".*?",?)/is';
- // $1 : the name of an FO object property
- // $2 : the value of an FO object property
- $replace = "\t".'$1 : $2'."\n\t";
- $i_max = count($matches[0]) - 1;
- for ($i=$i_max; $i>=0; $i--) {
- list($match, $start) = $matches[0][$i];
- $length = strlen($match);
- $properties = preg_replace($search, $replace, $matches[1][$i][0]);
- $str = substr_replace($str, 'var FO ={'."\n\t".$properties.'}', $start, $length);
- }
- } else {
- $str = preg_replace('/\s*(M.util.add_[^;]*;)\s*/', "\n\t".'$1'."\n", $str);
- }
- return $str;
- }
- /**
- * mediaplugin_filter
- *
- * @param xxx $courseid
- * @param xxx $text
- * @param xxx $options (optional, default=array)
- * @return xxx
- */
- function mediaplugin_filter($hotpot, $text, $options=array()) {
- // this function should be overloaded by the subclass
- return $text;
- }
- }
- /**
- * hotpot_mediaplayer
- *
- * @copyright 2010 Gordon Bateson
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @since Moodle 2.0
- */
- class hotpot_mediaplayer {
- public $aliases = array();
- public $playerurl = '';
- public $flashvars = array();
- public $flashvars_paramname = '';
- public $querystring_paramname = '';
- public $options = array(
- 'width' => 0, 'height' => 0, 'build' => 40,
- 'quality' => 'high', 'majorversion' => '6', 'flashvars' => null
- );
- public $more_options = array();
- public $media_filetypes = array();
- public $spantext = '';
- public $removelink = true;
- /**
- * contructor for this class
- */
- function __construct() {
- $this->options = array_merge($this->options, $this->more_options);
- }
- /**
- * generate
- *
- * @param xxx $filetype
- * @param xxx $link
- * @param xxx $mediaurl
- * @param xxx $options
- * @return xxx
- */
- function generate($filetype, $link, $mediaurl, $options) {
- global $CFG;
- // cache language strings
- static $str;
- if (! isset($str->$filetype)) {
- $str->$filetype = $filetype.'audio'; // get_string($filetype.'audio', 'mediaplugin');
- }
- // $id must be unique to prevent it being stored in Moodle's text cache
- static $id_count = 0;
- $id = str_replace('hotpot_mediaplayer_', '', get_class($this)).'_'.time().sprintf('%02d', ($id_count++));
- // add movie id to $options, if necessary
- // this is required in order to allow Flash addCallback on IE
- // 2009/11/30 - it is not necessary for IE8, maybe not necessary at all
- //if (! isset($options['id'])) {
- // $options['id'] = 'ufo_'.$id;
- //}
- // add movie url to $options, if necessary
- if (! isset($options['movie'])) {
- $options['movie'] = $this->playerurl;
- if ($this->querystring_paramname) {
- $options['movie'] .= '?'.$this->querystring_paramname.'='.$mediaurl;
- }
- }
- // do we need to make sure the mediaurl is added to flashvars?
- if ($this->flashvars_paramname && empty($options['skipmediaurl'])) {
- $find_mediaurl = true;
- } else {
- $find_mediaurl = false;
- }
- // get list of option names to be cleaned
- $search = '/^player|playerurl|querystring_paramname|flashvars_paramname|skipmediaurl$/i';
- $names = preg_grep($search, array_keys($options), PREG_GREP_INVERT);
- // clean the options
- foreach ($names as $name) {
- switch ($name) {
- case 'id':
- // allow a-z A-Z 0-9 and underscore (could use PARAM_SAFEDIR, but that allows hyphen too)
- $options[$name] = preg_replace('/\W/', '', $options[$name]);
- break;
- case 'movie':
- // clean_param() will reject url if it contains spaces
- $options[$name] = str_replace(' ', '%20', $options[$name]);
- $options[$name] = clean_param($options[$name], PARAM_URL);
- break;
- case 'flashvars':
- // split flashvars into an array
- $flashvars = str_replace('&', '&', $options[$name]);
- $flashvars = explode('&', $flashvars);
- // loop through $flashvars, cleaning as we go
- $options[$name] = array();
- $found_mediaurl = false;
- foreach ($flashvars as $flashvar) {
- if (trim($flashvar)=='') {
- continue;
- }
- list($n, $v) = explode('=', $flashvar, 2);
- $n = clean_param($n, PARAM_ALPHANUM);
- if ($n==$this->flashvars_paramname) {
- $found_mediaurl = true;
- $options[$name][$n] = clean_param($v, PARAM_URL);
- } else if (array_key_exists($n, $this->flashvars)) {
- $options[$name][$n] = clean_param($v, $this->flashvars[$n]);
- } else {
- // $flashvar not defined for this media player so ignore it
- }
- }
- // add media url to flashvars, if necessary
- if ($find_mediaurl && ! $found_mediaurl) {
- $n = $this->flashvars_paramname;
- $options[$name][$n] = clean_param($mediaurl, PARAM_URL);
- }
- // add flashvars values passed via $options
- foreach ($this->flashvars as $n => $type) {
- if (isset($options[$n])) {
- $options[$name][$n] = clean_param($options[$n], $type);
- unset($options[$n]);
- }
- }
- // rebuild $flashvars
- $flashvars = array();
- foreach ($options[$name] as $n => $v) {
- $flashvars[] = "$n=".$v; // urlencode($v);
- }
- // join $namevalues back together
- $options[$name] = implode('&', $flashvars);
- unset($flashvars);
- break;
- default:
- $quote = '';
- if (isset($options[$name])) {
- $value = $options[$name];
- if (preg_match('/^(\\\\*["'."']".')?(.*)'.'$1'.'$/', $value, $matches)) {
- $quote = $matches[1];
- $value = $matches[2];
- }
- $options[$name] = $quote.clean_param($value, PARAM_ALPHANUM).$quote;
- }
- } // end switch $name
- } // end foreach $names
- // re-order options ("movie" first, "flashvars" last)
- $names = array_merge(
- array('id'), array('movie'),
- preg_grep('/^id|movie|flashvars$/i', $names, PREG_GREP_INVERT),
- array('flashvars')
- );
- $args = array();
- $properties = array();
- foreach ($names as $name) {
- if (empty($options[$name])) {
- continue;
- }
- $args[$name] = $options[$name];
- $properties[] = $name.':"'.$this->obfuscate_js(addslashes_js($options[$name])).'"';
- }
- $properties = implode(',', $properties);
- if (strlen($this->spantext)) {
- $spantext = $this->spantext;
- } else {
- $size = '';
- if (isset($options['width'])) {
- $size .= ' width="'.$options['width'].'"';
- }
- if (isset($options['height'])) {
- $size .= ' height="'.$options['height'].'"';
- }
- $spantext = '<img src="'.$CFG->wwwroot.'/pix/spacer.gif"'.$size.' alt="'.$str->$filetype.'" />';
- }
- return $link
- .'<span class="mediaplugin mediaplugin_'.$filetype.'" id="'.$id.'">'.$spantext.'</span>'."\n"
- .'<script type="text/javascript">'."\n"
- .'//<![CDATA['."\n"
- .' var FO = { '.$properties.' };'."\n"
- .' UFO.create(FO, "'.$this->obfuscate_js($id).'");'."\n"
- .' UFO.main("'.$this->obfuscate_js($id).'");'."\n"
- .'//]]>'."\n"
- .'</script>'
- ;
- }
- /**
- * obfuscate_js
- *
- * @param xxx $str
- * @return xxx
- */
- function obfuscate_js($str) {
- global $CFG;
- if (empty($CFG->hotpot_enableobfuscate)) {
- return $str;
- }
- $obfuscated = '';
- $strlen = strlen($str);
- for ($i=0; $i<$strlen; $i++) {
- if ($i==0 || mt_rand(0,2)) {
- $obfuscated .= '\\u'.sprintf('%04X', ord($str{$i}));
- } else {
- $obfuscated .= $str{$i};
- }
- }
- return $obfuscated;
- }
- }