source: moodle/trunk/fuentes/filter/mediaplugin/filter.php @ 1331

Last change on this file since 1331 was 1331, checked in by jrpelegrina, 3 years ago

Updated to moodle 3.0.3

File size: 6.0 KB
Line 
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 *  Media plugin filtering
19 *
20 *  This filter will replace any links to a media file with
21 *  a media plugin that plays that media inline
22 *
23 * @package    filter
24 * @subpackage mediaplugin
25 * @copyright  2004 onwards Martin Dougiamas  {@link http://moodle.com}
26 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 */
28
29defined('MOODLE_INTERNAL') || die();
30
31/**
32 * Automatic media embedding filter class.
33 *
34 * It is highly recommended to configure servers to be compatible with our slasharguments,
35 * otherwise the "?d=600x400" may not work.
36 *
37 * @package    filter
38 * @subpackage mediaplugin
39 * @copyright  2004 onwards Martin Dougiamas  {@link http://moodle.com}
40 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41 */
42class filter_mediaplugin extends moodle_text_filter {
43    /** @var bool True if currently filtering trusted text */
44    private $trusted;
45    /** @var core_media_renderer Media renderer */
46    private $mediarenderer;
47    /** @var string Partial regex pattern indicating possible embeddable content */
48    private $embedmarkers;
49
50    public function filter($text, array $options = array()) {
51        global $CFG, $PAGE;
52
53        if (!is_string($text) or empty($text)) {
54            // non string data can not be filtered anyway
55            return $text;
56        }
57
58        if (stripos($text, '</a>') === false) {
59            // Performance shortcut - if not </a> tag, nothing can match.
60            return $text;
61        }
62
63        if (!$this->mediarenderer) {
64            $this->mediarenderer = $PAGE->get_renderer('core', 'media');
65            $this->embedmarkers = $this->mediarenderer->get_embeddable_markers();
66        }
67
68        // Check SWF permissions.
69        $this->trusted = !empty($options['noclean']) or !empty($CFG->allowobjectembed);
70
71        // Looking for tags.
72        $matches = preg_split('/(<[^>]*>)/i', $text, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
73
74        if (!$matches) {
75            return $text;
76        }
77
78        // Regex to find media extensions in an <a> tag.
79        $re = '~<a\s[^>]*href="([^"]*(?:' .  $this->embedmarkers . ')[^"]*)"[^>]*>([^>]*)</a>~is';
80
81        $newtext = '';
82        $validtag = '';
83        $sizeofmatches = count($matches);
84
85        // We iterate through the given string to find valid <a> tags
86        // and build them so that the callback function can check it for
87        // embedded content. Then we rebuild the string.
88        foreach ($matches as $idx => $tag) {
89            if (preg_match('|</a>|', $tag) && !empty($validtag)) {
90                $validtag .= $tag;
91
92                // Given we now have a valid <a> tag to process it's time for
93                // ReDoS protection. Stop processing if a word is too large.
94                if (strlen($validtag) < 4096) {
95                    $processed = preg_replace_callback($re, array($this, 'callback'), $validtag);
96                }
97                // Rebuilding the string with our new processed text.
98                $newtext .= !empty($processed) ? $processed : $validtag;
99                // Wipe it so we can catch any more instances to filter.
100                $validtag = '';
101                $processed = '';
102            } else if (preg_match('/<a\s[^>]*/', $tag) && $sizeofmatches > 1) {
103                // Looking for a starting <a> tag.
104                $validtag = $tag;
105            } else {
106                // If we have a validtag add to that to process later,
107                // else add straight onto our newtext string.
108                if (!empty($validtag)) {
109                    $validtag .= $tag;
110                } else {
111                    $newtext .= $tag;
112                }
113            }
114        }
115
116        // Return the same string except processed by the above.
117        return $newtext;
118    }
119
120    /**
121     * Replace link with embedded content, if supported.
122     *
123     * @param array $matches
124     * @return string
125     */
126    private function callback(array $matches) {
127        global $CFG, $PAGE;
128        // Check if we ignore it.
129        if (preg_match('/class="[^"]*nomediaplugin/i', $matches[0])) {
130            return $matches[0];
131        }
132
133        // Get name.
134        $name = trim($matches[2]);
135        if (empty($name) or strpos($name, 'http') === 0) {
136            $name = ''; // Use default name.
137        }
138
139        // Split provided URL into alternatives.
140        $urls = core_media::split_alternatives($matches[1], $width, $height);
141
142        $options = array();
143
144        // Allow SWF (or not).
145        if ($this->trusted) {
146            $options[core_media::OPTION_TRUSTED] = true;
147        }
148
149        // We could test whether embed is possible using can_embed, but to save
150        // time, let's just embed it with the 'fallback to blank' option which
151        // does most of the same stuff anyhow.
152        $options[core_media::OPTION_FALLBACK_TO_BLANK] = true;
153
154        // NOTE: Options are not passed through from filter because the 'embed'
155        // code does not recognise filter options (it's a different kind of
156        // option-space) as it can be used in non-filter situations.
157        $result = $this->mediarenderer->embed_alternatives($urls, $name, $width, $height, $options);
158
159        // If something was embedded, return it, otherwise return original.
160        if ($result !== '') {
161            return $result;
162        } else {
163            return $matches[0];
164        }
165    }
166}
Note: See TracBrowser for help on using the repository browser.