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); } }