diff --git a/filter/mediaplugin/filter.php b/filter/mediaplugin/filter.php
index 57e58d513dc1d..b71cb4989db01 100644
--- a/filter/mediaplugin/filter.php
+++ b/filter/mediaplugin/filter.php
@@ -68,18 +68,52 @@ public function filter($text, array $options = array()) {
// Check SWF permissions.
$this->trusted = !empty($options['noclean']) or !empty($CFG->allowobjectembed);
- // Handle all links that contain any 'embeddable' marker text (it could
- // do all links, but the embeddable markers thing should make it faster
- // by meaning for most links it doesn't drop into PHP code).
- $newtext = preg_replace_callback($re = '~]*href="([^"]*(?:' .
- $this->embedmarkers . ')[^"]*)"[^>]*>([^>]*)~is',
- array($this, 'callback'), $text);
-
- if (empty($newtext) or $newtext === $text) {
- // error or not filtered
+ // Looking for tags.
+ $matches = preg_split('/(]*>)/i', $text, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
+
+ if (!$matches) {
return $text;
}
+ // Regex to find media extensions in an tag.
+ $re = '~]*href="([^"]*(?:' . $this->embedmarkers . ')[^"]*)"[^>]*>([^>]*)~is';
+
+ $newtext = '';
+ $validtag = '';
+ $sizeofmatches = count($matches);
+
+ // We iterate through the given string to find valid tags
+ // and build them so that the callback function can check it for
+ // embedded content. Then we rebuild the string.
+ foreach ($matches as $idx => $tag) {
+ if (preg_match('||', $tag) && !empty($validtag)) {
+ $validtag .= $tag;
+
+ // Given we now have a valid tag to process it's time for
+ // ReDoS protection. Stop processing if a word is too large.
+ if (strlen($validtag) < 4096) {
+ $processed = preg_replace_callback($re, array($this, 'callback'), $validtag);
+ }
+ // Rebuilding the string with our new processed text.
+ $newtext .= !empty($processed) ? $processed : $validtag;
+ // Wipe it so we can catch any more instances to filter.
+ $validtag = '';
+ $processed = '';
+ } else if (preg_match('/]*/', $tag) && $sizeofmatches > 1) {
+ // Looking for a starting tag.
+ $validtag = $tag;
+ } else {
+ // If we have a validtag add to that to process later,
+ // else add straight onto our newtext string.
+ if (!empty($validtag)) {
+ $validtag .= $tag;
+ } else {
+ $newtext .= $tag;
+ }
+ }
+ }
+
+ // Return the same string except processed by the above.
return $newtext;
}
diff --git a/filter/mediaplugin/tests/filter_test.php b/filter/mediaplugin/tests/filter_test.php
index c0044fb6ab5a8..0148d4a8d870a 100644
--- a/filter/mediaplugin/tests/filter_test.php
+++ b/filter/mediaplugin/tests/filter_test.php
@@ -51,6 +51,15 @@ function test_filter_mediaplugin_link() {
$filterplugin = new filter_mediaplugin(null, array());
+ $longurl = 'my test file';
+ $longhref = '';
+
+ do {
+ $longhref .= 'a';
+ } while(strlen($longhref) + strlen($longurl) < 4095);
+
+ $longurl = 'my test file';
+
$validtexts = array (
'test mp3',
'test ogg',
@@ -76,7 +85,9 @@ function test_filter_mediaplugin_link() {
href="http://moodle.org/testfile/test.avi">test mp3
',
- 'youtube\'s'
+ 'youtube\'s',
+ // Test a long URL under 4096 characters.
+ $longurl
);
//test for valid link
@@ -86,6 +97,9 @@ function test_filter_mediaplugin_link() {
$this->assertNotEquals($text, $filter, $msg);
}
+ $insertpoint = strrpos($longurl, 'http://');
+ $longurl = substr_replace($longurl, 'http://pushover4096chars', $insertpoint, 0);
+
$invalidtexts = array(
'href="http://moodle.org/testfile/test.mp3"',
'test test',
@@ -101,7 +115,9 @@ function test_filter_mediaplugin_link() {
'test',
'test mp3',
'test mp3',
- 'test mp3'
+ 'test mp3',
+ // Test a long URL over 4096 characters.
+ $longurl
);
//test for invalid link
@@ -110,5 +126,11 @@ function test_filter_mediaplugin_link() {
$filter = $filterplugin->filter($text);
$this->assertEquals($text, $filter, $msg);
}
+
+ // Valid mediaurl followed by a longurl.
+ $precededlongurl = 'test.mp3'. $longurl;
+ $filter = $filterplugin->filter($precededlongurl);
+ $this->assertEquals(1, substr_count($filter, 'M.util.add_audio_player'));
+ $this->assertContains($longurl, $filter);
}
}